Fail2ban Setup Guide: Protect Your Server From Brute Force

What is fail2ban and how does it protect a server?
Fail2ban is open source software that reads your server log files and temporarily blocks IP addresses that make too many failed login attempts in a short time. It uses a firewall rule to do the blocking. It slows down password guessing bots, but it does not fix a weak password or an exposed service on its own.
We are a digital marketing and web team, not a hosting company. This guide follows the official fail2ban documentation and project files. If you own a website or an online store, you will learn how the decision works. If you manage your own VPS, you will also find the commands step by step.
However, the logic is simple. The service reads the log line by line, counts failed login traces, and keeps the source out for a while once a limit is crossed. When the time ends, the block ends. So a legitimate user who gets blocked by mistake is not locked out for good.
Marketing is affected too. If a site that pays for ads or SEO slows down under heavy login attempts, visitors leave. Also, landing pages open late when server resources run out. That is why infrastructure security, speed and conversion are directly linked. We covered the speed side in our guide on how site speed affects SEO.
How do fail2ban jails, filters and actions work together?
Fail2ban works with three concepts. A jail defines which service to watch, which log file to read and which limits apply. A filter is a set of regular expressions that spots a failed attempt in a log line. An action is the blocking command that runs once the limit is crossed.
- Jail: the service, the log path and the limits.
- Filter:
failregexdefines a failed attempt, andignoreregexdefines lines you want to skip. - Action: in most setups it adds a block rule to the firewall.
For example, the file layout mirrors this. Filters live in /etc/fail2ban/filter.d/ and actions live in action.d. You write jail definitions in jail.conf, jail.d and jail.local. The ready-made filters cover most common services, so you rarely need to write one from scratch.
A filter also pulls the attacker's address out of the line. It uses tags such as <HOST> for that. For example, the sshd jail reads the SSH log, matches lines with the sshd filter and then runs the block action.
Which attacks does fail2ban stop, and which does it miss?
Fail2ban works against repeated attempts that reach a log from the same source. SSH password guessing, admin panel logins and HTTP basic authentication failures are typical examples. It has limited effect on attacks that never reach a log or that come from thousands of sources.
| Situation | Fail2ban effect | Extra defense |
|---|---|---|
| Heavy SSH password guessing from one IP | Strong | Key based login, password login off |
| Repeated POST requests to a login page from one IP | Good, needs a custom filter | Two step verification |
| Slow attempts from thousands of IPs | Weak | Application layer protection, WAF |
| Weak or leaked password | None | Password policy, password manager |
| Request that exploits an application bug | None | Updates, WAF, code fix |
The last two rows matter. Many site owners install fail2ban and assume they are safe. However, if an attacker knows the right password, the log shows no failed login. Then fail2ban has nothing to act on.
In short, fail2ban is one security layer, not the whole answer. We cover application level flaws in our OWASP Top 10 guide.
What is the difference between brute force, password spraying and credential stuffing?
People often mix up these three terms, but each one behaves differently against fail2ban. OWASP describes them under authentication attacks. The difference lies in what the attacker tries and how fast.
- Brute force: the attacker tries many passwords on one account. It is easy to catch from a single source.
- Password spraying: the attacker tries a few common passwords on many accounts. The failure count per account stays low.
- Credential stuffing: the attacker tries username and password pairs from another breach.
Fail2ban suits the first type very well. In the other two, the attacker slows down or rotates addresses. So the attacker stays under the limits. For that reason, two step verification and unique passwords are a stronger defense than log based blocking.
What should you check before you install fail2ban?
First, settle five things before you start. Do you have root or sudo access? Can you reach the console from your provider's panel? Which firewall backend runs on the machine? Are the logs in files or in the systemd journal? Does traffic arrive directly, or does it pass through a CDN or reverse proxy?
- Write down your own IP address. You can use our IP lookup tool for that.
- Test that your provider's console or rescue access works.
- Confirm that you can restore your backup. Our website backup strategy guide explains how.
- Try the new rule on a test server or in a maintenance window first.
However, console access is the most valuable item on this list. Because if you block yourself over SSH, the provider's panel may be the only way back in. On the other hand, if you write a jail without knowing where the logs live, fail2ban sees nothing and gives you a false sense of safety.
This list may look boring. Still, most people who lock themselves out skipped one of these steps.
How do you install and start fail2ban?
In practice, the package is called fail2ban on most distributions. On the Debian and Ubuntu family, the commands below are enough. On Red Hat based systems the package often comes from an extra repository, so check your own distribution's documentation.
sudo apt update
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
The last command lists the running jails. Which jails come enabled after installation depends on the distribution. In the official jail.conf file, jails are off by default, and the file tells you to enable only the ones that fit your setup. So check the list with your own eyes.
Once the service is up, read /var/log/fail2ban.log. The first lines show which jails started. If something is wrong, you usually find the first hint there. Also, do not change settings right after installation. Watch the current state first, then move in small steps.
Why do you edit jail.local instead of jail.conf in fail2ban?
The official documentation says to leave .conf files unchanged. A package update can overwrite them. You put your customizations in .local files instead. Fail2ban also defines the load order clearly.
jail.confjail.d/*.conf(in alphabetical order)jail.localjail.d/*.local(in alphabetical order)
A later file overrides an earlier one. So you only need to put the lines you want to change into jail.local. Do not copy the whole file. A copy goes stale over time, so it causes odd behavior after updates.
For example, if you only want to change bantime, you write one line. Also, you do not need the headers or comments. After the change, sudo fail2ban-client reload loads the settings again and warns you about errors. Testing the configuration with sudo fail2ban-client -t before you go live is also a good habit.
What do bantime, findtime and maxretry mean?
These three settings are the heart of fail2ban. You can write times in seconds or with short forms such as 10m, 1h and 1d. In the current jail.conf file the defaults are bantime = 10m, findtime = 10m and maxretry = 5.
- bantime: how long a block lasts.
- findtime: the time window in which failures count.
- maxretry: how many failures inside that window trigger a block.
Read it like this: if maxretry failures pile up within the last findtime, fail2ban blocks the address for bantime. The three values work together, so rethink the others when you change one.
For example, picture a small case. If you set maxretry = 3 and findtime is very short, a slow attacker is never caught. On the other hand, if findtime is very long, a legitimate user who typed a wrong password days ago can hit the limit. So pick values that match how your team actually logs in. Also, if several people share one account, keep the limit a little looser.
Which fail2ban settings are a reasonable starting point?
Instead of a fixed rule, the right value depends on your traffic and how your team works. The table below is a starting range, not a guarantee. So watch your own logs and adjust.
| Profile | bantime | findtime | maxretry | Fits |
|---|---|---|---|---|
| Close to default | 10m | 10m | 5 | First trial, low risk |
| Balanced start | 1h | 10m | 5 | General purpose VPS |
| Strict | 1d | 10m | 3 | Server with key only login |
Example calculation: say maxretry = 5 and bantime = 1h. If a bot returns the moment a block ends, it goes through at most 24 block periods a day. It can make 5 attempts in each, so the upper limit is about 120 attempts. Progressive ban times lower that number further, as you will see below.
Instead, think of these numbers as a test bench. Start with a profile close to the default for the first week, watch the logs and confirm there are no false blocks. Then raise the time step by step. It sounds slow, but it cuts the risk of blocking your own team.
Also, the strict profile is only for servers where login needs a key. Legitimate users never type a password there, so the chance of crossing the limit by accident is low. But if password login is open, very short limits can block your own team.
How do you protect SSH logins with fail2ban?
Because SSH is the door attackers try the most, we start there. The official jail.conf already includes an sshd section, so you only enable it and tune the limits. Create the file as /etc/fail2ban/jail.local.
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
[sshd]
enabled = true
port = ssh
maxretry = 4
findtime = 10m
bantime = 1h
If you moved SSH to a non standard port, update the port line with the same value. Otherwise fail2ban applies the block to the wrong port. If your logs live in the journal instead of a file, you may need backend = systemd. Also, most packages set this for you. Still, run sudo fail2ban-client status sshd to confirm that the jail really works.
Is fail2ban enough on its own for SSH?
No. The first defense is to turn off password login. The PasswordAuthentication and PermitRootLogin options in the OpenSSH sshd_config file are described in the official man page. Once key based login works, you can switch password login off.
- Test key based login in a second session.
- Check the configuration with
sudo sshd -t. - Reload the service. The service name can be
sshorsshd. - Keep your current session open and test a new connection.
If you break this order, you can lock yourself out. Even then, fail2ban stays as a second layer and quiets any attempt that does not use a key. On a server where only key login is open, password guessing bots turn away at the door anyway. Still, the logs stay clean and wasted resources drop. For the option details, see the sshd_config man page.
How do you protect web login pages with fail2ban?
The official jail.conf includes ready jails such as nginx-http-auth and apache-auth. They read HTTP basic authentication failures from the error logs. For the own login form of an application like WordPress, you write a custom filter.
First create /etc/fail2ban/filter.d/wp-login.conf. The example assumes the combined access log format. If your log format differs, adapt the expression.
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php HTTP/[0-9.]+" 200
ignoreregex =
Then add the jail to jail.local. The log path depends on your web server and distribution.
[wp-login]
enabled = true
port = http,https
filter = wp-login
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 10m
bantime = 1h
This filter counts only POST requests that return 200. WordPress shows the form again after a failed login and usually redirects after a good one. The approach has a limit, though. If the attacker hits another address, the filter does not see it. XML-RPC, for example, needs its own filter. Still, verify it on your own site; the test tool in the next section is for that.
How do you test a custom filter with fail2ban-regex?
Test your filter with the fail2ban-regex tool before you go live. The tool takes a log file and a filter file and reports how many lines match. It also shows the lines that did not match, so fixing the expression is easy.
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wp-login.conf
If the match count is zero, there are three possible reasons. The log format differs from what you expected, the expression is wrong, or the log has no failed logins at all. On the other hand, if too many lines match, the expression is too broad and may block legitimate users too.
You do not need a real attack to test. Existing log lines are enough, because the tool runs them through the filter and shows the result. Also, you can change the expression and run the test again to compare results.
So before you go live, check whether your own IP address appears in the matched list. If it does, add it to the ignoreip list.
How do you check the fail2ban ban list and jail status?
You do most daily work with the fail2ban-client command. We took the syntax from the official man page. The examples below use only reserved documentation IP blocks.
| Command | What it does |
|---|---|
sudo fail2ban-client status | Lists the running jails |
sudo fail2ban-client status sshd | Shows jail status and banned IPs |
sudo fail2ban-client banned | Lists banned IPs per jail |
sudo fail2ban-client set sshd unbanip 203.0.113.50 | Removes the block on an IP |
sudo fail2ban-client set sshd banip 198.51.100.7 | Blocks an IP by hand |
sudo fail2ban-client reload | Reloads settings without stopping the service |
To see the firewall side, sudo iptables -L -n or sudo nft list ruleset lists the rules, depending on your backend. That way you confirm the block is really in place. When you read the output, look at the spread of addresses, not only the count. If one address shows up again and again, progressive ban times make sense. If you see many different addresses, the attack is distributed, and blocking alone will not be enough.
Fail2ban writes its own records to /var/log/fail2ban.log by default. If you wonder who owns a blocked address, our WHOIS lookup tool can help.
How do you use progressive ban times and the recidive jail for repeat offenders?
If the same address returns after a block, you can lengthen the time on every round. The official jail.conf describes the bantime.increment setting for this. Fail2ban looks up earlier blocks in its database and grows the time by doubling it: 1, 2, 4, 8 and so on. The bantime.maxtime setting sets the upper limit.
[DEFAULT]
bantime.increment = true
bantime.maxtime = 604800
The value 604800 seconds equals one week. You can also choose the growth factor with bantime.factor, and you can decide with bantime.overalljails whether the history of all jails is searched.
As an alternative, the recidive jail watches fail2ban's own log and blocks repeat offenders for a long time. The section in the official file has bantime = 1w and findtime = 1d. Before you enable it, think about whether these values are too harsh for you.
How do you reduce the risk of locking yourself out with fail2ban?
However, the most common mistake is blocking your own IP. Typing a wrong password several times, running a deploy script with a wrong key, or having colleagues behind the same office address make mistakes can all cause it.
- If you have a fixed IP, add it to the
ignoreiplist. - Keep a second SSH session open while you change the configuration.
- Test your provider's console or rescue access beforehand.
- Use a short
bantimeduring tests, then raise it. - If you suspect a configuration error, test it with
sudo fail2ban-client -t.
Should you get locked out, remove your own block from the console with fail2ban-client set sshd unbanip. If you have no console access, provider support may be the only way out. In that case, tell the support team your address and the time you were locked out. That way the fix comes faster. Also, write down the cause so it does not happen again.
How do you write the fail2ban whitelist (ignoreip) correctly?
According to the official documentation, ignoreip is the list of addresses that are never blocked. You can enter a single IP, a CIDR block or a host name. You separate the entries with spaces.
ignoreip = 127.0.0.1/8 ::1 203.0.113.10 198.51.100.0/24
Keep the list short. If you add a whole office network, everyone on it can try without limit. Also, if you use a host name, you depend on the lookup working. With a dynamic IP, the rule breaks when the address changes.
To add an address on a running system for a short time, the fail2ban-client set sshd addignoreip command exists. However, this change does not last, so write it into jail.local to keep it. Also, instead of every team member adding their own address, a secure VPN exit address is easier to manage.
How does fail2ban behave behind a CDN or reverse proxy?
If a CDN or reverse proxy sits in front of your site, the web server may log the proxy's address, not the visitor's. In that case fail2ban blocks the wrong address. Worse, thousands of legitimate visitors stand behind the same proxy address.
- First, confirm that the log shows the real visitor address.
- If it does not, set up the web server's real IP module as your proxy provider's documentation describes.
- Or do the blocking in the CDN's own security rules.
There is a subtle point too. If traffic comes through the CDN, a firewall block on the origin server does not stop the visitor, because the connecting address is the CDN. So in this setup, solve log and IP visibility first, then write rules.
An easy way to check is to try a login from your own phone on mobile data and see which address appears in the log. If your phone's address shows up, the real IP arrives correctly.
Can fail2ban block legitimate bots such as Googlebot?
Yes, it can, because a filter that is too broad catches more than you intend. For example, a filter that treats many 404 responses as an attack can also catch a search engine bot. Then crawl problems start and your search visibility suffers.
- Limit the filter to sensitive addresses such as login forms.
- Avoid broad rules such as a general 404 counter.
- If a blocked address looks like a search engine bot, verify its identity.
Google describes how to verify Googlebot in its official documentation. See the Googlebot verification guide for the details. You can also inspect a suspicious address with our IP lookup tool. That way you avoid blocking a legitimate bot by mistake.
Is fail2ban enough, and how do CSF and ModSecurity complement it?
However, fail2ban is reactive. It sees a behavior after it lands in a log and then blocks it. It does not inspect request content. A web application firewall, or WAF, does that job. CSF is a tool that makes firewall rules easier to manage.
You can compare layered defense to an apartment building. The firewall is the building door, the WAF is the camera at the desk, and fail2ban is the guard who walks away anyone who keeps forcing the same door. None of them closes every risk alone. So knowing each layer's job helps you invest in the right place.
We cover CSF Firewall and ModSecurity in separate sibling guides, so we will not repeat them here. In short: fail2ban looks at behavior, a WAF looks at request content, and the firewall decides which doors stay open.
On top of these you need current software, strong passwords and regular backups. For the HTTPS side, see our SSL certificate guide.
How do you troubleshoot fail2ban when it does not work?
Narrow the problem down layer by layer. First confirm the service is running, then that the jail loaded, then that the filter matches lines, and finally that the block reaches the firewall. Apply changes one at a time. Otherwise you cannot tell which step helped.
- Check the service with
sudo systemctl status fail2ban. - Look for errors in
sudo journalctl -u fail2banand in/var/log/fail2ban.log. - See whether your jail appears in the
sudo fail2ban-client statusoutput. - Then, if the jail is missing, check the
enabled = trueline and look for typos. - Confirm with
fail2ban-regexthat the filter really matches. - Review the
logpathandbackendvalues for your distribution. - Check that the block rule exists in the firewall. The command depends on the backend.
If no block rule appears, look at the banaction value. The official default is iptables-multiport. If your system uses a different firewall, choose the matching action from the action.d folder.
How do you review a fail2ban setup on a regular basis?
Also, installation is not a job you do once and forget. A distribution update, a web server change or a log format change can break filters without any warning. So set up a small maintenance routine.
- Once a month, run
fail2ban-client statusto confirm that the jails are up. - Review the blocked addresses and look for false blocks.
- After updates, run the
fail2ban-regextest again. - Keep a copy of
jail.localin a safe place. - Remove addresses from
ignoreipthat are no longer valid.
That way you notice a problem on a calm day, not in the middle of an attack.
When should you leave fail2ban to your hosting provider?
However, not every owner needs to configure this on their own server. The honest test is this: can you roll back when you make a mistake? If you cannot, leave the job to the provider.
- On shared hosting you have no root access, so you cannot install fail2ban. The provider manages security.
- If you buy a managed VPS or server service, ask the provider first, because clashing rules cause trouble.
- Without console or rescue access, do not accept the lockout risk.
- Do not change a critical online store without a maintenance window.
- If you cannot solve real IP visibility behind a CDN, do not go further.
The right hosting choice takes most of this load off you. For the criteria, see our guide to choosing web hosting. For work on the software of your site, we support you with our custom software development and web design services. We still advise leaving server management to the right specialist. That approach protects both your security and your business continuity. Also, the cost of a wrong configuration is usually higher than the cost of maintenance.
What is the best order to follow for fail2ban in the end?
Here is a short roadmap. Apply each step after the previous one, one at a time, and test it.
- Confirm your console access and your backup.
- Set up key based SSH login and consider turning password login off.
- Install fail2ban and write only the settings you need into
jail.local. - Enable the
sshdjail first and confirm withstatusthat it works. - If needed, write a custom filter for web login and test it with
fail2ban-regex. - Review progressive ban times and the
ignoreiplist. - Read
/var/log/fail2ban.logon a regular basis.
Remember one more thing: security is not a project you finish once. Software gets updates, attack styles change and teams grow. So keep the steps in this guide as a checklist and review them from time to time. If you are unsure about a step, stop, go back to the official documentation or ask your provider.
For official sources, see the fail2ban project repository, the jail.conf file and the jail.conf man page. To inspect your domain and DNS records, our DNS lookup tool can also help.



