Fail2ban — Protecting Your Homelab from Brute Force Attacks

📆 · ⏳ 6 min read · ·

Introduction

Running a homelab means exposing services to the internet, which inevitably attracts unwanted attention. Within days of setting up my first SSH server in the cloud, I started seeing hundreds of failed login attempts in my logs from IP addresses around the world. These brute force attacks weren’t just annoying - they were a real security risk.

This is where fail2ban became a game-changer in my homelab security setup. Instead of manually tracking and blocking suspicious IPs, fail2ban does the heavy lifting by automatically detecting and preventing these attacks before they become a problem.

What is Fail2ban?

Fail2ban ↗️ is an open-source intrusion prevention tool that monitors your system logs and automatically blocks IP addresses that show signs of malicious activity. Think of it as an automated security guard that never sleeps.

Here’s how it works:

  1. Monitors log files (like /var/log/auth.log) for suspicious patterns
  2. Detects repeated failures using configurable regex filters
  3. Automatically bans IPs by updating firewall rules (iptables)
  4. Unbans after timeout or manually when needed
  5. Sends notifications when actions are taken

Key Features:

  • Multiple “jails” for different services (SSH, web servers, etc.)
  • Configurable ban duration and failure thresholds
  • IP whitelisting to prevent self-banning
  • Integration with notification systems
  • Support for IPv4 and IPv6
💡

Important Note

Fail2ban reduces attack frequency but isn’t a complete security solution. You still need strong authentication, SSH keys, and other security practices.

Setup Fail2ban

I recommend installing fail2ban directly on your host system for better log access and firewall integration.

Installation

Ubuntu/Debian:

Terminal window
sudo apt update
sudo apt install fail2ban

CentOS/RHEL:

Terminal window
sudo yum install epel-release
sudo yum install fail2ban

Basic Configuration

Create local configuration files (prevents updates from overwriting your settings):

Terminal window
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local

Edit /etc/fail2ban/jail.local with your basic settings:

[DEFAULT]
# Ban IP for 1 hour
bantime = 3600
# 5 failed attempts within 10 minutes triggers ban
findtime = 600
maxretry = 5
# Whitelist your trusted IPs (IMPORTANT: Add your admin IPs)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 YOUR_ADMIN_IP
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3

Start and Test

Terminal window
# Enable and start fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Check status
sudo fail2ban-client status
sudo fail2ban-client status sshd
Eternal Vault Logo

Eternal Vault is Now Live! 🎉

Secure your digital legacy with Eternal Vault — now launched and available for everyone! Store your passwords, documents, and critical info in a zero-knowledge encrypted vault. If you ever stop checking in, your chosen loved ones are notified and given access, ensuring your legacy is protected and responsibly passed on.

🚀 Built & launched by me

Discord Notifications Setup

Getting instant alerts when IPs get banned helps monitor your homelab’s security. Here’s how to set up Discord notifications.

Create Discord Webhook

  1. Open Discord → Go to your desired channel
  2. Channel Settings → Integrations → Webhooks
  3. Create Webhook → Copy the URL

Configure Discord Action

Create the Discord notification script at /etc/fail2ban/scripts/discord-notify.sh:

#!/bin/bash
# Discord webhook URL - update this with your webhook URL
WEBHOOK_URL="https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN"
# Script parameters
ACTION="$1"
IP="$2"
JAIL="$3"
HOSTNAME="$4"
FAILURES="$5"
BANTIME="$6"
send_discord_notification() {
local embed_json="$1"
curl -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "$embed_json" \
--silent --output /dev/null
}
case "$ACTION" in
"ban")
embed_json=$(cat <<EOF
{
"username": "Fail2Ban",
"embeds": [{
"title": "🔨 IP Address Banned",
"description": "A malicious IP has been automatically blocked by Fail2ban",
"color": 15158332,
"fields": [
{
"name": "🎯 Banned IP",
"value": "\`$IP\`",
"inline": true
},
{
"name": "🏠 Host",
"value": "$HOSTNAME",
"inline": true
},
{
"name": "🔒 Jail",
"value": "$JAIL",
"inline": true
},
{
"name": "❌ Failed Attempts",
"value": "$FAILURES",
"inline": true
},
{
"name": "⏱️ Ban Duration",
"value": "$BANTIME seconds",
"inline": true
},
{
"name": "🔍 IP Lookup",
"value": "[Check IP Info](https://db-ip.com/$IP)",
"inline": true
}
]
}]
}
EOF
)
send_discord_notification "$embed_json"
;;
"unban")
embed_json=$(cat <<EOF
{
"username": "Fail2Ban",
"embeds": [{
"title": "🔓 IP Address Unbanned",
"description": "An IP address has been automatically unbanned",
"color": 3066993,
"fields": [
{
"name": "🎯 Unbanned IP",
"value": "\`$IP\`",
"inline": true
},
{
"name": "🏠 Host",
"value": "$HOSTNAME",
"inline": true
},
{
"name": "🔒 Jail",
"value": "$JAIL",
"inline": true
}
]
}]
}
EOF
)
send_discord_notification "$embed_json"
;;
esac

Make it executable:

Terminal window
sudo mkdir -p /etc/fail2ban/scripts
sudo chmod +x /etc/fail2ban/scripts/discord-notify.sh

Create the fail2ban action file /etc/fail2ban/action.d/discord.conf:

[Definition]
actionban = /etc/fail2ban/scripts/discord-notify.sh ban <ip> <name> <fq-hostname> <failures> <bantime>
actionunban = /etc/fail2ban/scripts/discord-notify.sh unban <ip> <name> <fq-hostname>

Test your setup:

Terminal window
# Test ban notification
/etc/fail2ban/scripts/discord-notify.sh ban "192.168.1.100" "sshd" "homelab-server" "5" "3600"
# Test unban notification
/etc/fail2ban/scripts/discord-notify.sh unban "192.168.1.100" "sshd" "homelab-server"

Configure Jails

Instead of modifying jail.local, create individual jail configuration files in /etc/fail2ban/jail.d/. This is a better practice for organization and maintenance.

Create SSH protection (/etc/fail2ban/jail.d/ssh.conf):

/etc/fail2ban/jail.d/ssh.conf
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
findtime = 600
bantime = 3600
action = %(action_mwl)s
discord

Create web server protection (/etc/fail2ban/jail.d/nginx.conf):

/etc/fail2ban/jail.d/nginx.conf
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
action = %(action_mwl)s
discord
[nginx-noscript]
enabled = true
filter = nginx-noscript
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 6
action = %(action_mwl)s
discord

Why the jail.d Approach is Better:

  • Modular configuration: Each service gets its own config file
  • Easy management: Enable/disable services by renaming files
  • Version control friendly: Track changes per service
  • No merge conflicts: Updates won’t overwrite your custom configs
  • Clean organization: Easy to see what’s protected at a glance
  • Selective enabling: Just delete/rename files to disable specific jails

Restart fail2ban: sudo systemctl restart fail2ban

How I Use Fail2ban in My Homelab

In my current setup, fail2ban protects several critical services:

Protected Services:

  • SSH on all servers (most important)
  • Nginx reverse proxy (protects all web services behind it)
  • Vaultwarden password manager
  • Jellyfin media server

My Configuration:

[DEFAULT]
bantime = 86400 # 24-hour bans
findtime = 3600 # 1-hour detection window
maxretry = 3 # Strict 3-strike policy
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 100.64.0.0/10 # Include Tailscale range

Real Results Since Implementation:

  • Thousands of malicious IPs blocked automatically
  • Instant Discord alerts keep me informed
  • Zero manual intervention needed for basic attacks

Best Practices and Tips

Essential Security Practices

  1. Always whitelist your admin IPs in ignoreip to prevent lockouts
  2. Use SSH keys instead of passwords when possible
  3. Test your configuration before going live: sudo fail2ban-client -t
  4. Monitor logs regularly: sudo tail -f /var/log/fail2ban.log

Useful Commands

Terminal window
# Check all active jails
sudo fail2ban-client status
# Check specific jail details
sudo fail2ban-client status sshd
# Manually ban/unban an IP
sudo fail2ban-client set sshd banip 192.168.1.100
sudo fail2ban-client set sshd unbanip 192.168.1.100
# Check banned IPs
sudo iptables -L -n | grep DROP

Common Gotchas

  • Self-banning: Always whitelist your admin IPs
  • Log permissions: Ensure fail2ban can read your log files
  • Firewall conflicts: Make sure fail2ban can modify iptables rules
  • Testing carefully: Don’t test bans from your primary admin IP

Conclusion

Fail2ban has become essential in my homelab security setup. It’s not just about stopping attacks - it provides visibility into what’s targeting your services and responds automatically to threats.

The setup is straightforward, and the peace of mind is invaluable. Combined with Discord notifications, I get real-time security insights without constantly monitoring logs.

Remember: fail2ban is one layer in your security stack. Use it alongside strong firewall rules, VPN access, and proper authentication for comprehensive protection.

Have you set up fail2ban in your homelab? What services do you protect, and how do you handle notifications? Share your experiences in the comments below, or reach out to me on Twitter ↗️ / Reddit ↗️.

Stay secure, and happy homelabbing! 🛡️

You may also like

  • # homelab# selfhosted# security

    Authelia — Self-hosted Single Sign-On (SSO) for your homelab services

    Authelia is a powerful authentication and authorization server that provides secure Single Sign-On (SSO) for all your self-hosted services. Perfect for adding an extra layer of security to your homelab.

  • # homelab# selfhosted

    SearXNG — Privacy-focused metasearch engine for your homelab

    SearXNG is a privacy-focused metasearch engine that aggregates results from various search engines. Learn how to set it up and configure it for optimal privacy and performance.

  • # homelab# selfhosted

    Stirling PDF — Self-hosted PDF manipulation powerhouse

    Stirling PDF is a powerful, locally hosted web application that allows you to perform various operations on PDF files. Learn how to set it up and automate PDF processing in your homelab.