Introduction
A practical, production-ready setup for SSH, Postfix, Dovecot and HTTPD — plus monitoring & reporting scripts
Rocky Linux 10 continues the RHEL tradition of being a stable, long-term server operating system. But stability alone does not equal security. Any internet-exposed server will face constant brute-force attacks — especially on SSH, mail services and web authentication endpoints.
In this article, we will build a solid, maintainable Fail2Ban setup on Rocky Linux 10 to protect:
sshd(SSH access)postfix(SMTP)dovecot(IMAP / POP3)httpd(Apache authentication + common web attacks)
We will also add operational scripts to verify that Fail2Ban is working correctly and that blocked IPs are actually enforced at the firewall level.
This guide assumes:
- Rocky Linux 10
systemdfirewalld- Logs handled via
journaldor classic log files
Why Fail2Ban?
Fail2Ban is not a firewall replacement — it is an intelligent log-driven intrusion prevention layer.
It works by:
- Watching service logs for authentication failures
- Detecting suspicious behavior patterns
- Temporarily banning attacker IPs via the firewall
This approach is lightweight, effective, and perfectly suited for SSH and mail services.
1. Installing Fail2Ban on Rocky Linux 10
sudo dnf install -y fail2ban
sudo systemctl enable --now fail2ban
Verify it is running:
systemctl status fail2ban
fail2ban-client status
2. Configuration Philosophy
Never edit jail.conf directly.
All customizations go into:
/etc/fail2ban/jail.local
This ensures upgrades never overwrite your configuration.
3. Production-Ready jail.local
Below is a clean, explicit configuration suitable for real servers.
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
bantime = 3600
findtime = 600
maxretry = 5
backend = systemd
# Mail notifications (optional but recommended)
destemail = root@localhost
sender = fail2ban@localhost
action = %(action_mwl)s
SSH Protection
[sshd]
enabled = true
port = ssh
logpath = /var/log/secure
maxretry = 5
SSH is the most attacked service on any Linux server. This jail alone will reduce noise dramatically.
Postfix (SMTP) Protection
[postfix]
enabled = true
port = smtp,submission,465
logpath = /var/log/maillog
maxretry = 5
This prevents SMTP brute-force attempts against mail accounts.
Dovecot (IMAP / POP3) Protection
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps
logpath = /var/log/maillog
maxretry = 5
Essential if users access mail via IMAP or POP3.
HTTPD Authentication Protection
Apache does not usually log failed logins in access logs — instead they appear in error logs.
[httpd]
enabled = true
port = http,https
logpath = /var/log/httpd/*error_log
filter = apache-auth
maxretry = 5
This protects:
.htaccessprotected areas- BasicAuth / DigestAuth endpoints
- Admin panels protected by Apache auth
Web Brute-Force & Bot Protection
Create a separate jail for common web attack patterns. BUT first: check if the file is already existing. If not follow these steps:
[httpd-bot]
enabled = true
port = http,https
logpath = /var/log/httpd/*access_log
filter = apache-badbots
maxretry = 3
bantime = 7200
Now create the filter:
sudo nano /etc/fail2ban/filter.d/apache-badbots.conf
[Definition]
failregex = <HOST> -.*"(GET|POST).*(wp-login\.php|xmlrpc\.php|roundcube/).*HTTP/.*"
ignoreregex =
This blocks common attack targets such as:
- WordPress login
- XML-RPC abuse
- Webmail brute-force attempts
4. Reload and Verify
sudo fail2ban-client reload
sudo fail2ban-client status
Expected output:
Jail list: sshd, postfix, dovecot, httpd, httpd-bot
5. How Fail2Ban Integrates with firewalld
On Rocky Linux, Fail2Ban typically blocks IPs using firewalld rich rules.
You can see them with:
sudo firewall-cmd --zone=public --list-rich-rules
Each banned IP should appear as a reject rule.
6. Maintenance & Reporting Script
The following script shows:
- Which IPs are banned per jail
- In which firewalld zone they are blocked
fail2ban_firewall_status.sh
#!/bin/bash
echo "=== Fail2Ban Firewall Status ==="
echo
jails=$(fail2ban-client status | awk -F: '/Jail list/ {gsub(/, /," "); print $2}')
zones=$(firewall-cmd --get-zones)
for jail in $jails; do
echo "Jail: $jail"
ips=$(fail2ban-client status "$jail" | awk -F': ' '/Banned IP list/ {print $2}')
if [ -z "$ips" ]; then
echo " No banned IPs"
else
for ip in $ips; do
found=0
for zone in $zones; do
if firewall-cmd --zone="$zone" --list-rich-rules | grep -qw "$ip"; then
echo " $ip → blocked in zone '$zone'"
found=1
fi
done
[ $found -eq 0 ] && echo " WARNING: $ip not found in firewalld!"
done
fi
echo
done
Make it executable:
chmod +x /usr/local/bin/fail2ban_firewall_status.sh
7. Operational Best Practices
- Review Fail2Ban logs periodically:
journalctl -u fail2ban - Keep ban times reasonable (1–2 hours)
- Do not permanently ban IPs unless necessary
- Combine Fail2Ban with:
- SSH key-only authentication
- Rate limiting at the web layer
- Proper TLS configuration
Fail2Ban is most effective as part of a layered defense strategy.
Summary
Fail2Ban remains one of the most effective and lightweight security tools for Linux servers — especially on enterprise-grade platforms like Rocky Linux 10.
In this guide, we:
- Built a clean, production-ready Fail2Ban configuration
- Protected SSH, mail services and Apache
- Added web brute-force detection
- Integrated with
firewalld - Created a maintenance & reporting script for operational visibility
The result is a quiet, hardened server that automatically reacts to attacks — without manual intervention.
Fail2Ban won’t replace a firewall, but used correctly, it dramatically reduces attack surface and log noise, making your Rocky Linux server safer and easier to operate.
If you maintain internet-facing systems, this setup should be part of your baseline hardening checklist.
Views: 6
