How to Automatically Block Suspicious IPs using iptables and Fail2Ban

Your Linux server is under attack right now you just might not know it yet. Every internet-facing machine faces a constant stream of brute-force login attempts, port scans, and automated bots probing for vulnerabilities. Passwords get guessed, services get hammered, and logs fill up with thousands of failed attempts every single day.
The good news is that you do not need expensive security software to stop most of it. Two tools already available in every major Linux distribution iptables and Fail2Ban give you everything you need to detect malicious traffic and cut it off at the network level, automatically and in real time.
In this guide, we will walk through how to install and configure both tools, write a custom IP blocker script, and wire everything together into a robust, automated defense layer. Whether you manage a single VPS, a web server, or a home lab, this setup will dramatically reduce your attack surface with minimal ongoing effort.
Quick Win: This entire setup — from installation to automated blocking — can be fully operational in under 20 minutes, with no reboots and no paid tools required.
Why Relying on Default Firewall Settings is Not Enough
A freshly installed Linux server comes with basic firewall capabilities, but without active monitoring and automated response, your defense is entirely passive. Here is what you are exposed to without iptables rules and Fail2Ban in place:
- Brute-Force SSH Attacks — Automated scripts attempt thousands of username/password combinations per hour against your SSH port.
- Service-Specific Exploits — Web servers, mail servers, and database services each have their own attack patterns that need targeted monitoring.
- Slow-Rate Attacks — Some attackers deliberately pace their attempts to stay below threshold detection, making manual monitoring impractical.
- Log Flooding — Unmitigated attacks generate enormous log volumes, masking legitimate events and making auditing harder.
- Resource Drain — Even failed login attempts consume CPU, memory, and network bandwidth — enough to degrade server performance over time.
- Compliance Exposure — Many regulatory frameworks require demonstrable controls to detect and respond to unauthorized access attempts.
Security Note: Used together, iptables provides the firewall enforcement layer while Fail2Ban supplies the intelligence — detecting attack patterns and updating firewall rules dynamically without manual intervention.
Core Configuration Settings
| Setting / Parameter | Purpose |
| maxretry = 5 | Number of failures before an IP is banned |
| bantime = 3600 | Duration of the ban in seconds (3600 = 1 hour) |
| findtime = 600 | Time window in seconds during which failures are counted |
| logpath | Log file Fail2Ban monitors for the specified jail/service |
| filter = sshd | Built-in Fail2Ban filter that matches SSH failure log patterns |
| action = customblock | Points Fail2Ban to your custom IP blocker script for banning |
| nullok (PAM flag) | Allows logins for users not yet enrolled in 2FA during rollout |
Step-by-Step: Setting Up Automated IP Blocking
Step 1 — Install iptables and Fail2Ban
Start by making sure both tools are installed on your server. They are available in the default package repositories for all major distributions.
On Ubuntu / Debian:
sudo apt update
sudo apt install iptables fail2ban -y
On RHEL / Rocky Linux / AlmaLinux / CentOS:
sudo yum install iptables-services fail2ban -y
Tip: On RHEL-based systems, enable and start both services after installation: sudo systemctl enable –now iptables fail2ban
Step 2 — Create the Custom IP Blocker Script
A dedicated bash script gives you a clean, reusable command for manually blocking any IP address — and later, a hook for Fail2Ban to call automatically.
Create the script file:
sudo nano /usr/local/bin/block-ip.sh
Paste the following content into the file:
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: $0 <IP_ADDRESS>"
exit 1
fi
IP=$1
# Check if IP is already blocked
if iptables -L INPUT -v -n | grep -q "$IP"; then
echo "IP $IP is already blocked."
else
iptables -A INPUT -s $IP -j DROP
echo "IP $IP has been blocked."
fi
Save and exit (CTRL+O, then CTRL+X), then make the script executable:
sudo chmod +x /usr/local/bin/block-ip.sh
Test it by blocking a sample IP:
Test it by blocking a sample IP:
You should see: IP 192.168.1.100 has been blocked.
Confirm the rule was added to iptables:
sudo iptables -L -n -v
Tip: This script is especially useful when you spot a suspicious IP in your logs and want to block it immediately without navigating iptables syntax directly.
Step 3 — Configure Fail2Ban to Monitor SSH
Fail2Ban organizes its monitoring rules into ‘jails’ — each jail watches a specific service log and responds when attack patterns are detected. We will configure the SSH jail now.
Create or edit the local jail configuration file:
sudo nano /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
findtime = 600
For RHEL-based systems, update the logpath to match where SSH logs are stored:
logpath = /var/log/secure
Restart Fail2Ban to apply the new jail configuration:
sudo systemctl restart fail2ban
Verify the SSH jail is active and monitoring correctly:
sudo fail2ban-client status sshd
This command shows the number of currently banned IPs, total failure counts, and jail status. To unban a specific IP that was automatically blocked:
sudo fail2ban-client set sshd unbanip 192.168.1.100
Step 4 — Connect Fail2Ban to Your Custom Script (Optional)
By default, Fail2Ban manages its own iptables rules internally. If you want Fail2Ban to call your custom script instead — for example, to add extra logging, send alerts, or execute additional logic — you can configure a custom action.
Create a new Fail2Ban action definition file:
sudo nano /etc/fail2ban/action.d/customblock.conf
Paste the following action definition:
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = /usr/local/bin/block-ip.sh <ip>
actionunban = iptables -D INPUT -s <ip> -j DROP
[Init]
Now update your jail.local to use this custom action:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
findtime = 600
action = customblock
Restart Fail2Ban to activate the custom action:
sudo systemctl restart fail2ban
Tip: The custom action approach is especially valuable if you want to write blocked IPs to a separate audit log, trigger a notification webhook, or sync bans across multiple servers.
Step 5 — Make iptables Rules Persistent Across Reboots
By default, iptables rules are held in memory and are lost when the server restarts. To make your blocks survive reboots, you need to persist them.
On Ubuntu / Debian — install the persistence package and save current rules:
sudo apt install iptables-persistent -y
sudo netfilter-persistent save
On RHEL / Rocky / AlmaLinux / CentOS:
# Option 1 - using the service
sudo service iptables save
# Option 2 - manually save to config file
sudo iptables-save > /etc/sysconfig/iptables
Important: Without persisting your rules, every server reboot will clear all IP blocks — including those added by Fail2Ban. Always save rules after configuring your firewall.
Verifying Everything is Working
Before rolling this out fully, confirm the setup is behaving as expected. Here are four reliable verification checks:
- Active Jail Status — Run sudo fail2ban-client status sshd to confirm the jail is running and showing current ban counts.
- iptables Rule Inspection — Run sudo iptables -L -n to view all active blocking rules, including those added by both your script and Fail2Ban.
- Deliberate Failure Test — From a secondary machine or IP, attempt to SSH with wrong credentials 5+ times. The IP should be banned and subsequent attempts should time out.
- Log Review — Check /var/log/fail2ban.log to see ban and unban events in real time.
⚠️ Important: Always test from a secondary IP address or machine, never from your active management session. Getting locked out of your own server is a real risk if firewall rules are misconfigured.
What Services Should You Protect?
Fail2Ban supports jails for many services beyond SSH. Here is a recommended starting point for most server environments:
| Service | Jail Name | What It Protects Against |
| SSH | sshd | Brute-force login attempts on port 22 |
| Apache HTTP | apache-auth | Failed authentication attempts to web app login pages |
| Nginx | nginx-http-auth | Repeated 401/403 responses indicating login scanning |
| Postfix (Mail) | postfix | SMTP authentication failures and spam relay attempts |
| ProFTPD / vsftpd | proftpd / vsftpd | Failed FTP login attempts |
| WordPress | wordpress (custom) | XML-RPC abuse and wp-login brute-force attacks |
Conclusion
Automated IP blocking with iptables and Fail2Ban is one of the most practical and immediately effective security controls you can add to a Linux server. It requires no ongoing management once configured — Fail2Ban silently monitors your logs, detects attacks as they happen, and updates your firewall rules without any manual intervention.
Adding a custom bash script on top of that gives you the flexibility to extend the system however you need whether that means triggering email alerts, writing to a centralized audit log, or syncing bans across a fleet of servers. The building blocks are simple, the logic is transparent, and the protection is real.






