When dealing with Fail2Ban on Ubuntu 14.04 (though this applies to modern systems too), we often see cases where:
1. Fail2Ban correctly detects brute-force attempts
2. The iptables chain gets created
3. The banned IP appears in the chain
4. BUT...connections from the IP still succeed
The classic symptom appears when running SSH on non-standard ports. The default jail configuration:
[ssh]
enabled = true
port = ssh # Problematic for custom ports
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
Changing to the actual port (e.g., 32323) causes iptables errors because Fail2Ban's default iptables-multiport
action has specific limitations.
When switching to:
banaction = iptables-allports
The system now blocks all ports rather than just the specified service port. This works because:
- It creates broader iptables rules that aren't port-specific
- Bypasses the multiport module limitations
- Matches all traffic from banned IPs regardless of destination port
Instead of using allports (which is overkill), create a custom action file /etc/fail2ban/action.d/iptables-custom.conf
:
[Definition]
actionstart = iptables -N fail2ban-
iptables -A fail2ban- -j RETURN
iptables -I INPUT -p tcp --dport -j fail2ban-
actionstop = iptables -D INPUT -p tcp --dport -j fail2ban-
iptables -F fail2ban-
iptables -X fail2ban-
actioncheck = iptables -n -L INPUT | grep -q 'fail2ban-[ \t]'
actionban = iptables -I fail2ban- 1 -s -j REJECT
actionunban = iptables -D fail2ban- -s -j REJECT
After implementing any changes, verify with:
sudo fail2ban-client status ssh
sudo iptables -L -n -v
Test the actual blocking by attempting connections from a banned IP while monitoring:
tail -f /var/log/fail2ban.log
- Security Impact: iptables-allports affects all services, not just SSH
- Performance: Large ban lists may impact iptables performance
- Alternatives: Consider using nftables instead for modern systems
For Ubuntu 18.04+ systems, the preferred solution would be migrating to nftables-based banning which handles custom ports more elegantly.
When troubleshooting Fail2Ban on Ubuntu servers, one particularly frustrating scenario occurs when the system appears to be functioning correctly - rules are being created in iptables, bans are being logged - but the banned IPs can still connect. Here's what's happening under the hood:
# Example of proper ban in logs
2023-07-15 10:45:22,881 fail2ban.actions: WARNING [sshd] Ban 192.168.1.100
# iptables chain shows the rule
Chain fail2ban-sshd (1 references)
target prot opt source destination
REJECT all -- 192.168.1.100 anywhere reject-with icmp-port-unreachable
RETURN all -- anywhere anywhere
The root cause becomes clear when examining the INPUT chain rules. For non-standard SSH ports, Fail2Ban's default iptables-multiport
action only blocks the specified ports, but the chain may not be properly referenced in the INPUT chain:
# Standard configuration mismatch
iptables -L INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
fail2ban-ssh tcp -- anywhere anywhere multiport dports ssh
Notice how this references the default SSH port (22) even when your service runs on port 32323.
Option 1: Using iptables-allports
Changing to banaction = iptables-allports
works because it blocks all ports for banned IPs. This is effective but has collateral damage:
[sshd]
enabled = true
port = 32323
banaction = iptables-allports
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
Option 2: Custom Action with Port Specification
A more surgical approach creates a custom action file:
# /etc/fail2ban/action.d/iptables-custom.conf
[Definition]
actionstart = iptables -N fail2ban-
iptables -A fail2ban- -j RETURN
iptables -I INPUT -p tcp --dport -j fail2ban-
actionstop = iptables -D INPUT -p tcp --dport -j fail2ban-
iptables -F fail2ban-
iptables -X fail2ban-
actioncheck = iptables -n -L INPUT | grep -q 'fail2ban-[ \t]'
actionban = iptables -I fail2ban- 1 -s -j REJECT
actionunban = iptables -D fail2ban- -s -j REJECT
Then reference it in your jail:
[sshd]
enabled = true
port = 32323
banaction = iptables-custom
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
After making changes, verify the complete iptables ruleset:
iptables -L -n -v --line-numbers
iptables -L INPUT -n -v --line-numbers
iptables -L fail2ban-sshd -n -v
Test by intentionally failing SSH logins from a test IP while monitoring:
tail -f /var/log/fail2ban.log
tail -f /var/log/auth.log
For stubborn cases, add temporary logging rules before your Fail2Ban chain:
iptables -I INPUT -p tcp --dport 32323 -j LOG --log-prefix "[SSH-AUTH] "
Then monitor kernel logs to see packet flow:
tail -f /var/log/kern.log