Stop Brute Force with fail2ban: SSH & WordPress Jails
Cut most SSH and WordPress login attacks with one tool. Install fail2ban, lock down jails, and verify bans—practical steps for Australian site owners, plus when to book Fixwebnode.
If your WordPress site or VPS is hammered by repeated login attempts, fail2ban is the single control that stops most of that noise before it becomes a breach. This guide walks Australian homeowners and small-business owners through installing fail2ban, configuring jails, and enabling SSH plus WordPress protection on a typical Linux host—so you can ban abusive IPs automatically instead of watching auth logs fill up.
At Fixwebnode WordPress Support we harden remote servers for clients across Australia every week. Below is the same practical path we use: real packages, copy-paste commands, verification, and clear points where DIY stops and a specialist should take over.
Why fail2ban matters for WordPress and SSH in Australia
Open SSH and wp-login.php attract constant credential stuffing from global botnets. Australia-based sites are not exempt—attackers scan the whole internet. fail2ban watches log files, matches failed-auth patterns, and updates the firewall (usually iptables or nftables via the firewall backend) so repeat offenders are blocked for a set time. One well-tuned jail set routinely cuts the bulk of automated brute-force traffic without changing your passwords or moving the site.
We work remotely with VPS and cloud hosts used by Australian businesses. Geography does not change the install; what changes is how quickly you notice lockouts, timezone in logs, and whether your host already ships a partial fail2ban package. For where we support clients, see all service areas.
How do we stop most brute-force attacks on WordPress and SSH with fail2ban in Australia?
Install fail2ban from your distro packages, enable the SSH jail, add a filter and jail for WordPress login failures, then reload and confirm bans with fail2ban-client status. That single stack—watch logs, match failures, ban IP—stops the majority of automated password guessing against SSH and wp-login.php without rewriting the site.
Use the table as a quick triage map before you dive into full steps.
| Symptom | Quick fix | When to call Fixwebnode |
|---|---|---|
| SSH flooded with failed passwords | Enable sshd jail; lower maxretry | You lock yourself out or use non-standard SSH ports/logs |
| wp-login.php hammered; CPU/spikes | WordPress filter + jail on auth log | Custom login URL, reverse proxy, or missing log lines |
| fail2ban running but zero bans | Check filter regex and log path | Log format mismatch after panel/PHP upgrades |
Common issues when deploying fail2ban for SSH and WordPress
These are distinct failure modes we see on production boxes—not generic “security tips.”
- Issue 1 — SSH jail never bans (or bans the wrong traffic):
fail2ban-client status sshdshows the jail active butCurrently bannedstays 0 while/var/log/auth.log(orsecure) fills with failures. Often the log path, backend, orsshdlog level does not match the stock filter. - Issue 2 — WordPress brute force continues after “enabling” fail2ban: Only the default SSH jail is on. There is no filter reading web or PHP logs for “authentication failure” / “Login failed” lines, so
wp-login.phpandxmlrpc.phpstay open to bots. - Issue 3 — You lock out legitimate admins (including yourself): Aggressive
maxretry/findtimeplus shared office NATs or failed SFTP scripts ban your own IP. SSH drops mid-session; WordPress shows repeated blocks from the same office range. - Issue 4 — Service fails to start after a config edit: A typo in
jail.localor a missing filter file causesfail2ban.serviceto exit; nothing is protecting the host until fixed.
Install fail2ban (Debian/Ubuntu and RHEL-family)
Prerequisites: root or sudo, a supported Linux VPS, SSH access from a stable IP, and firewall tools already present (iptables, nftables, or firewalld—fail2ban will drive the ban action).
Step 1 — Update packages and install
Debian/Ubuntu:
sudo apt update
sudo apt install -y fail2ban
RHEL, AlmaLinux, Rocky:
sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalld
Step 2 — Enable and start the service
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban --no-pager
Expect active (running). If the unit failed, jump to the troubleshooting section before adding jails.
Step 3 — Prefer jail.local over editing jail.conf
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Package upgrades overwrite jail.conf; your lasting settings belong in jail.local and drop-in files under /etc/fail2ban/jail.d/.
Configure the jail defaults (the “one setting” baseline)
Global defaults control how aggressive bans are. For most small WordPress hosts we start conservative, then tighten after ignore lists are correct.
Step 1 — Set sensible defaults in jail.local
Under the [DEFAULT] section, set values similar to:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
backend = auto
banaction = iptables-multiport
Adjust banaction if your host uses firewalld (firewallcmd-ipset or distro defaults) or nftables. Always add your office or home public IP to ignoreip before lowering maxretry.
Step 2 — Reload and verify defaults loaded
sudo fail2ban-client reload
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd bantime
If get commands error because sshd is not enabled yet, enable the SSH jail next, then re-check.
Enable SSH protection
Stock filters ship with fail2ban for OpenSSH. Your job is to turn the jail on and point it at the correct auth log.
Step 1 — Confirm where SSH failures are logged
sudo grep -E "Failed password|Invalid user" /var/log/auth.log | tail -n 20
# RHEL-family often uses:
sudo grep -E "Failed password|Invalid user" /var/log/secure | tail -n 20
If those files are empty, check journald-only setups:
sudo journalctl -u ssh -u sshd --since "1 hour ago" | tail -n 50
Step 2 — Enable the sshd jail
In /etc/fail2ban/jail.local or a drop-in:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 4
findtime = 10m
bantime = 1h
If SSH listens on a non-standard port, set port = 2222 (example) to match.
Step 3 — Reload and inspect the jail
sudo systemctl reload fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
You should see the jail listed, a filter name, and eventually banned IPs as failures accumulate.
Step 4 — Manual ban test (safe)
sudo fail2ban-client set sshd banip 203.0.113.10
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 203.0.113.10
Use a documentation-range IP you do not need. Confirm your firewall rules update, then unban.
Enable WordPress protection
WordPress does not ship a fail2ban jail. You add a filter that matches failed logins in the web or PHP log, then a jail that uses it. Two common patterns: (A) auth failures written to the syslog/auth log via a small mu-plugin or host feature, or (B) parsing the web server access/error log for POST storms on wp-login.php and xmlrpc.php. Prefer real authentication-failure lines when you can; access-log rate jails are a fallback.
Step 1 — Decide the log source
If your host or security plugin writes lines like WordPress authentication failure into /var/log/auth.log, use that path. Otherwise use the site access log, for example /var/log/nginx/access.log or the vhost log under /var/log/apache2/.
Step 2 — Create a WordPress filter
sudo nano /etc/fail2ban/filter.d/wordpress.conf
Example filter for syslog-style auth failures (adjust the failregex to match your exact log line):
[Definition]
failregex = ^%(__prefix_line)sWordPress authentication failure.*\s<HOST>
^%(__prefix_line)s.*Authentication failure for .* from <HOST>
ignoreregex =
Example fallback filter for nginx access logs (failed POSTs to login endpoints—tune to your log format):
[Definition]
failregex = ^<HOST> -.*"POST /wp-login\.php
^<HOST> -.*"POST /xmlrpc\.php
ignoreregex =
Step 3 — Add the WordPress jail
sudo nano /etc/fail2ban/jail.d/wordpress.local
[wordpress]
enabled = true
filter = wordpress
logpath = /var/log/auth.log
backend = auto
maxretry = 5
findtime = 10m
bantime = 1h
port = http,https
If you use the access-log approach, set logpath to the real vhost access log and keep port = http,https.
Step 4 — Test the regex against sample lines
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/wordpress.conf
Or for access logs:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress.conf
You want a non-zero match count on real failure lines and zero false matches on normal traffic. Fix failregex until that is true.
Step 5 — Reload and confirm the jail
sudo fail2ban-client reload
sudo fail2ban-client status wordpress
Optional: reduce xmlrpc abuse at the application layer as well (disable pingback if unused), but the jail still belongs in fail2ban so repeat offenders hit the firewall.
How to fix each common issue (DIY runbook)
Fix issue 1 — SSH jail active but no bans
- Confirm failures exist in the log fail2ban reads (
auth.log/secure/ journal). - Run
sudo fail2ban-regex %(sshd_log)s /etc/fail2ban/filter.d/sshd.confor point explicitly at the log file path. - In the sshd jail, set
logpathexplicitly if the default macro is wrong. - Ensure
backendmatches how logs are written (systemdvs file). - Reload:
sudo fail2ban-client reloadand re-checkstatus sshd.
Book Fixwebnode when SSH is chrooted, terminated at a bastion, or logs are shipped only to a remote collector so local filters never see failures.
Fix issue 2 — WordPress still under brute force
- Verify only
sshdis listed infail2ban-client status; ifwordpressis missing, add the filter and jail above. - Confirm failed logins produce lines in the chosen
logpath(trigger a failed login from a test browser). - Run
fail2ban-regexuntil matches appear. - Watch
sudo tail -f /var/log/fail2ban.logduring a test failure for “Ban” lines. - If you use Cloudflare or another reverse proxy, ban the real client IP only if the log shows it—otherwise you may ban the proxy edge. That design needs careful
prefer-forwarded/ log format work.
Call a pro when login URLs are custom, Multisite paths differ, or PHP runs in containers with logs outside the host path fail2ban watches.
Fix issue 3 — Locked out admins
- From console/VNC/host panel (not SSH), add your IP: edit
ignoreipin[DEFAULT]. - Unban immediately:
sudo fail2ban-client unban --allorsudo fail2ban-client set sshd unbanip YOUR.IP. - Raise
maxretryslightly and lengthenfindtimeif a shared NAT serves many staff. - Prefer SSH keys and disable password auth once keys work—fail2ban then sees far fewer legitimate retries.
- Document the office IP so future reloads keep
ignoreipintact.
If the only access path is SSH and you are already banned with no provider console, you need host-level recovery—Fixwebnode can coordinate that remotely with your VPS provider when you still have panel access.
Fix issue 4 — fail2ban will not start after edits
- Check syntax noise:
sudo fail2ban-client -tandsudo journalctl -u fail2ban -e --no-pager. - Revert the last jail/filter change; keep a known-good
jail.localcopy. - Confirm filter file names match the
filter =value (no.confsuffix in the jail option). - Start again:
sudo systemctl restart fail2banand verifystatus.
When configs were heavily customised by a control panel, specialist review avoids fighting the panel’s managed files.
Verification checklist (do this before you walk away)
sudo systemctl is-active fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client status wordpress
sudo tail -n 100 /var/log/fail2ban.log
Optionally confirm firewall counters (example for iptables):
sudo iptables -L -n | head -n 80
You want fail2ban chains present and growing ban lists under real attack traffic—not empty jails after a noisy weekend.
When DIY is enough vs when to book Fixwebnode
DIY is enough when you have sudo on a standard Ubuntu/Debian or RHEL-like VPS, stock OpenSSH, a single WordPress vhost with predictable logs, and console access if you misconfigure a ban. Follow the install, jail defaults, SSH, and WordPress sections above, keep ignoreip accurate, and re-check fail2ban-client status weekly at first.
Book Fixwebnode when any of these apply: you already locked out production access; WordPress sits behind Cloudflare/load balancers with complex real-IP headers; logs are only in Docker or a panel path that changes on upgrade; you need coordinated hardening (SSH keys, xmlrpc policy, WAF rules) without downtime; or fail2ban-regex never matches after honest DIY attempts. We are a direct remote WordPress and server specialist for Australian small businesses—not a freelance marketplace—and we work the live host with you.
Talk to Fixwebnode about fail2ban and WordPress hardening
If you want this applied and verified on your server—or you are mid-incident with SSH or wp-login under fire—start a conversation with the team via WordPress Support for Australian small businesses. Bring SSH/panel access details and we will focus on jails, filters, and safe ignore lists so brute-force noise drops without locking out your staff.
Remote delivery covers the full path in this article: install fail2ban, configure jail defaults, enable SSH protection, and add WordPress protection with proof via fail2ban-client status and log matches. That is how we stop the bulk of automated brute-force attacks with one disciplined control plane instead of endless password resets.