Swiss...
Fail2ban Configuration Guide: Protect Your SSH from Brute Force Attacks
Comprehensive guide to hardening SSH with Fail2ban
January 20, 2026
by SwissLayer 8 min read
why-swiss-hosting-for-privacy

Hardening SSH with Fail2ban: A Comprehensive SysAdmin Guide

1. Executive Summary

Fail2ban is an intrusion prevention framework that protects server services from brute-force and other automated attacks by scanning log files and banning IPs in the host firewall. This guide provides a production-ready configuration for SSH hardening, including custom jail tuning, firewall integration, and alignment with Swiss security standards (BSI/OSI).

2. What is Fail2ban and How Does It Work?

Fail2ban operates as a stateless daemon composed of three core components:

1. Filters: Regex patterns that search log files (e.g., /var/log/auth.log) for failed authentication attempts. 2. Jails: Define which filters trigger actions, what services to ban, and how long the ban lasts. 3. Actions: Shell scripts (typically firewall rule modifications) that enforce the ban by adding a block rule to the OS firewall.

Workflow:

Log Event → Filter Match → Retry Counter Increases → Max Retries Hit → Action Triggered (IP Ban)

3. Installation

⚠️ Prerequisite: Ensure you have root/sudo access. Never configure Fail2ban remotely until you test on a console or ensure you have an out-of-band access method (like VNC/IPMI), as misconfiguration can lock you out.

Ubuntu / Debian (Debian-based)
sudo apt update

sudo apt install fail2ban -y sudo systemctl enable fail2ban sudo systemctl start fail2ban

CentOS / RHEL / Rocky / AlmaLinux (RPM-based)
Note: On RHEL 8+/CentOS Stream, install from EPEL or AppStream.
sudo dnf install epel-release -y

sudo dnf install fail2ban -y sudo systemctl enable fail2ban sudo systemctl start fail2ban

4. Core Configuration: The jail.local Rule

Golden Rule: Never edit /etc/fail2ban/jail.conf. It will be overwritten on updates. Always create /etc/fail2ban/jail.local.

Create the override file:

sudo nano /etc/fail2ban/jail.local

Paste the following baseline SSH configuration:

[DEFAULT]

# Ignore internal traffic (replace with your specific subnets) ignoreip = 127.0.0.1/8, ::1, 10.0.0.0/8, 192.168.0.0/16

# Ban duration: 10 minutes (600 seconds) bantime = 600

# Number of attempts before ban: 5 maxretry = 5

# Window to count attempts: 10 minutes (600 seconds) findtime = 600

# Backend detection for log files backend = auto

# Actions (Default) # Use iptables for legacy, nftables for modern (RHEL 9+, Debian 11+) action = %(action_mwl)s

[sshd] enabled = true port = ssh filter = sshd logpath = %(sshd_logpath)s maxretry = 5 bantime = 1h action = iptables[name=SSH, protocol=tcp, port=ssh]

Key Configuration Notes:

- logpath: For Ubuntu/Debian, usually /var/log/auth.log. For CentOS/RHEL, usually /var/log/secure. - action: iptables is the standard, but for newer distributions, nftables is preferred. - nftables Action: action = nftables[name=SSH, protocol=tcp, port=ssh]

5. Custom Filter & Jail Creation

While the built-in SSHD filter is robust, you may need to handle specific scenarios (e.g., custom auth logs, or integrating with a custom app).

Scenario: Creating a Custom Filter for "Failed Logins"

If you have an application that logs specific failure patterns:

1. Create the filter:

sudo mkdir -p /etc/fail2ban/filter.d

sudo nano /etc/fail2ban/filter.d/myapp-auth.conf

2. Content:

[Definition]

failregex = Failed password for (.*? from)?

3. Create the jail: In /etc/fail2ban/jail.local:

[myapp-jail]

enabled = true port = http,https filter = myapp-auth logpath = /var/log/myapp/auth.log bantime = 3600 action = iptables[name=MyApp, protocol=tcp]

Scenario: Firewall Integration (iptables vs firewalld)

If you are running CentOS/RHEL with firewalld, use the following action line:

action = firewallcmd-name=ssh
Note: Ensure the firewall service is active before starting Fail2ban.

6. Real-World Tuning: Recidive & Whitelisting

The recidive Jail

A "recidive" jail is a second layer of defense. If an IP hits the ban threshold multiple times across different jails, it gets permanently banned (or for a long duration).

Add to /etc/fail2ban/jail.local:

[recidive]

enabled = true logpath = %(sshd_logpath)s maxretry = 3 bantime = 10d ignoreip = 127.0.0.1/8

Logic: If an IP is banned 3 times by any other jail, it enters the Recidive jail for 10 days.
Whitelisting (ignoreip)

Crucial for preventing self-lockout during updates or automated scripts.

1. Identify your IPs: Use ip addr or ifconfig. 2. Add to ignoreip:

[DEFAULT]

ignoreip = 127.0.0.1, ::1, 192.168.1.100, 10.0.0.0/24

Aggressive Tuning (Production)

If you have a known hostile environment, tighten the parameters:

[sshd]

enabled = true maxretry = 3 bantime = 3600 # 1 hour findtime = 600

7. Monitoring and Log Analysis

Live Status Checks
# Check system status

sudo fail2ban-client status

# Check specific jail status sudo fail2ban-client status sshd

# See banned IPs currently sudo fail2ban-client get sshd banned

Log Analysis

Fail2ban writes events to /var/log/fail2ban.log. Use tail for real-time monitoring:

sudo tail -f /var/log/fail2ban.log

Look for lines containing: - FAIL (Triggering a filter) - RESTART (Service restarts) - BAN (IP blocked) - UNBAN (Time elapsed or manual unbanning)

Automated Health Check Script

Create a script to alert if Fail2ban is running or IPs are banned:

#!/bin/bash

if ! systemctl is-active --quiet fail2ban; then echo "CRITICAL: Fail2ban is not running!" >> /var/log/fail2ban_alerts.log # Add notification webhook call here fi

8. Security Best Practices & Pitfalls

🚫 Pitfall: Locking Yourself Out

* Risk: Banning your own IP when testing remotely. * Fix: Always whitelist your management IP in ignoreip. * Mitigation: Ensure you have console access (IPMI/VNC) before enabling.

🚫 Pitfall: Config File Overwrite

* Risk: jail.conf changes during updates, wiping your custom config. * Fix: You must use jail.local. Settings in this file override jail.conf.

🚫 Pitfall: False Positives

* Risk: A legitimate user triggers the ban due to a bad password. * Fix: Adjust maxretry (default 5) and ensure findtime is wide enough to catch legitimate users. Monitor logs to identify high-frequency IPs that aren't malicious.

🚫 Pitfall: Performance

* Risk: Reading massive log files can slow down the daemon. * Fix: Use backend = inotify for real-time file monitoring (available in newer versions). Edit /etc/fail2ban/jail.local:

[DEFAULT]

backend = inotify

9. Alignment with Swiss Security Standards (BSI/OSI)

Swiss organizations typically align with BSI IT-Grundschutz (often the basis for Swiss Federal Administration standards) and LINFO (Law on Information Security).

1. BSI IT-Grundschutz COM.1.1.3 (Host Protection)

* Requirement: Hosts must be protected against unauthorized access. * Implementation: Fail2ban acts as a "Host Intrusion Prevention System." It prevents unauthorized SSH access by limiting password guessing. * Alignment: Your configuration ensures that only authenticated users access the shell, meeting the "Protection against password guessing" control.

2. BSI IT-Grundschutz BS.1.2.2 (Log Management)

* Requirement: Security-relevant events must be logged. * Implementation: Fail2ban logs all bans, fails, and restarts to /var/log/fail2ban.log. * Action: Ensure log rotation is configured (/etc/logrotate.d/fail2ban). Retain logs for at least 3-6 months depending on organizational policy to meet audit requirements.

3. LINFO & Swiss Data Protection (FADP)

* Requirement: Processing personal data (IP addresses are considered personal data in Switzerland). * Implementation: - Limit the scope: ignoreip ensures only internal traffic is trusted; IPs are stored locally. - Access Control: Fail2ban automatically locks out IPs, enforcing the "Principle of Least Privilege" for external access. - Incident Response: The banlist serves as an initial forensic log for analyzing attack vectors.

Implementation Checklist for Compliance:

1. [ ] Log Retention: Configure logrotate for /var/log/fail2ban.log. 2. [ ] Whitelist Review: Document why specific IPs are in ignoreip. 3. [ ] Audit Trail: Verify /var/log/fail2ban.log is writable by the system but not readable by standard users. 4. [ ] Multi-Factor Auth: Fail2ban is a layer, not a silver bullet. For high-security Swiss environments, combine Fail2ban with SSH Keys + 2FA (e.g., Google Authenticator).

10. Final Verification Steps

Run these commands to ensure a clean state:

# 1. Reload configuration (safe to reload)

sudo fail2ban-client reload

# 2. Check for configuration errors sudo fail2ban-client -x

# 3. Verify iptables rules (Check if chains exist) sudo iptables -L fail2ban-ssh -n

# 4. Verify firewall state sudo systemctl status firewalld # Or ufw status / systemctl status fail2ban

Conclusion

By following this guide, you move beyond basic installation to a hardened, compliant, and maintainable security posture suitable for enterprise Swiss standards.

About SwissLayer

SwissLayer provides secure, high-performance hosting in Switzerland - fully aligned with Swiss security standards and data protection laws.

🔒 Learn more: https://www.swisslayer.com