In today's digital landscape, server security is paramount. One powerful tool in your security arsenal is Fail2Ban. This blog post will guide you through setting up Fail2Ban on a Debian 12 system, incorporating best practices for 2024.
Fail2Ban is an intrusion prevention software framework that protects your server from brute-force attacks. It works by monitoring log files for suspicious activity and temporarily banning IP addresses that show malicious signs.
Below is a bash script that automates the installation and configuration of Fail2Ban on Debian 12. We'll break it down section by section to understand its functionality:
#
# _nnnn_
# dGGGGMMb
# @p~qp~~qMb
# M|@||@) M|
# @,----.JM|
# JS^\__/ qKL
# dZP qKRb
# dZP qKKb
# fZP SMMb
# HZM MMMM
# FqM MMMM
# __| ". |\dS"qML
# | `. | `' \Zq
# _) \.___.,| .'
# \____ )MMMMMP| .'
# `-' `--'
#
# Debian 12 Fail2Ban Clean Install
# By: 16BitMiker (v2024-10-27)
#
# ~~~~~~~~~~~~~~~~ BEGIN
# Enable debugging output
set -x
# Don't exit on error, but log it
set +e
log_error() {
echo "ERROR: $1" >&2
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ REMOVAL
echo "Checking if Fail2Ban is installed..."
if dpkg -s fail2ban &> /dev/null; then
echo "Fail2Ban is installed. Proceeding with removal..."
echo "Stopping and disabling Fail2Ban..."
sudo systemctl stop fail2ban || log_error "Failed to stop Fail2Ban"
sudo systemctl disable fail2ban || log_error "Failed to disable Fail2Ban"
echo "Removing Fail2Ban..."
sudo DEBIAN_FRONTEND=noninteractive apt-get purge --auto-remove fail2ban -y || log_error "Failed to purge Fail2Ban"
else
echo "Fail2Ban is not installed. Skipping removal steps."
fi
echo "Removing any remaining Fail2Ban files..."
sudo rm -rf /etc/fail2ban 2>/dev/null || log_error "Failed to remove /etc/fail2ban"
sudo rm -f /var/lib/fail2ban/fail2ban.sqlite3 2>/dev/null || log_error "Failed to remove fail2ban.sqlite3"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INSTALL
echo "Updating package lists..."
sudo DEBIAN_FRONTEND=noninteractive apt-get update -y || log_error "Failed to update package lists"
echo "Installing Fail2Ban and rsyslog..."
sudo DEBIAN_FRONTEND=noninteractive apt-get install fail2ban rsyslog -y || log_error "Failed to install Fail2Ban and rsyslog"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CONFIGURATION
echo "Configuring Fail2Ban..."
sudo mkdir -p /etc/fail2ban || log_error "Failed to create /etc/fail2ban directory"
sudo tee /etc/fail2ban/jail.local <<EOF || log_error "Failed to create jail.local"
[DEFAULT]
bantime = 86400
findtime = 3600
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
EOF
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SYSTEMCTL
echo "Ensuring rsyslog is running..."
sudo systemctl start rsyslog || log_error "Failed to start rsyslog"
sudo systemctl enable rsyslog || log_error "Failed to enable rsyslog"
echo "Starting and enabling Fail2Ban..."
sudo systemctl start fail2ban || log_error "Failed to start Fail2Ban"
sudo systemctl enable fail2ban || log_error "Failed to enable Fail2Ban"
# Wait for Fail2Ban to fully start
sleep 5
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STATUS
echo "Fail2Ban Status:"
sudo systemctl status fail2ban --no-pager || log_error "Failed to get Fail2Ban status"
echo "Fail2Ban SSH Jail Status:"
sudo fail2ban-client status sshd || log_error "Failed to get SSH jail status"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LOGS
echo "Recent Fail2Ban Logs:"
sudo journalctl -u fail2ban -n 50 --no-pager || log_error "Failed to retrieve Fail2Ban logs"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TROUBLESHOOTING
echo "Checking Fail2Ban configuration:"
sudo fail2ban-client -t || log_error "Fail2Ban configuration test failed"
echo "Checking if auth.log exists:"
ls -l /var/log/auth.log || log_error "auth.log not found"
echo "Checking permissions of Fail2Ban socket:"
ls -l /var/run/fail2ban/fail2ban.sock || log_error "Fail2Ban socket not found"
echo "Checking rsyslog status:"
sudo systemctl status rsyslog --no-pager || log_error "Failed to get rsyslog status"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END
set +x
echo "Fail2Ban installation and configuration complete."
echo "Please review any ERROR messages above."
Let's break down the script section by section:
# ASCII art and script information...
# Enable debugging output
set -x
# Don't exit on error, but log it
set +e
log_error() {
echo "ERROR: $1" >&2
}
This section sets up the script environment:
The shebang (#!/bin/bash
) specifies that this is a bash script.
set -x
enables debugging output, showing each command as it's executed.
set +e
prevents the script from exiting on errors, allowing it to continue even if some commands fail.
The log_error
function is defined to log error messages.
echo "Checking if Fail2Ban is installed..."
if dpkg -s fail2ban &> /dev/null; then
echo "Fail2Ban is installed. Proceeding with removal..."
echo "Stopping and disabling Fail2Ban..."
sudo systemctl stop fail2ban || log_error "Failed to stop Fail2Ban"
sudo systemctl disable fail2ban || log_error "Failed to disable Fail2Ban"
echo "Removing Fail2Ban..."
sudo DEBIAN_FRONTEND=noninteractive apt-get purge --auto-remove fail2ban -y || log_error "Failed to purge Fail2Ban"
else
echo "Fail2Ban is not installed. Skipping removal steps."
fi
echo "Removing any remaining Fail2Ban files..."
sudo rm -rf /etc/fail2ban 2>/dev/null || log_error "Failed to remove /etc/fail2ban"
sudo rm -f /var/lib/fail2ban/fail2ban.sqlite3 2>/dev/null || log_error "Failed to remove fail2ban.sqlite3"
This section checks if Fail2Ban is already installed and removes it if present:
It uses dpkg -s
to check if Fail2Ban is installed.
If installed, it stops and disables the service, then purges it using apt-get
.
It also removes any remaining configuration files and the SQLite database.
echo "Updating package lists..."
sudo DEBIAN_FRONTEND=noninteractive apt-get update -y || log_error "Failed to update package lists"
echo "Installing Fail2Ban and rsyslog..."
sudo DEBIAN_FRONTEND=noninteractive apt-get install fail2ban rsyslog -y || log_error "Failed to install Fail2Ban and rsyslog"
This section updates the package lists and installs Fail2Ban along with rsyslog:
DEBIAN_FRONTEND=noninteractive
ensures the installation runs without requiring user input.
Both fail2ban
and rsyslog
are installed.
echo "Configuring Fail2Ban..."
sudo mkdir -p /etc/fail2ban || log_error "Failed to create /etc/fail2ban directory"
sudo tee /etc/fail2ban/jail.local <<EOF || log_error "Failed to create jail.local"
[DEFAULT]
bantime = 86400
findtime = 3600
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
EOF
This section creates a custom configuration file for Fail2Ban:
It creates /etc/fail2ban/jail.local
, which overrides the default configuration.
The configuration sets global parameters and a specific jail for SSH.
echo "Ensuring rsyslog is running..."
sudo systemctl start rsyslog || log_error "Failed to start rsyslog"
sudo systemctl enable rsyslog || log_error "Failed to enable rsyslog"
echo "Starting and enabling Fail2Ban..."
sudo systemctl start fail2ban || log_error "Failed to start Fail2Ban"
sudo systemctl enable fail2ban || log_error "Failed to enable Fail2Ban"
# Wait for Fail2Ban to fully start
sleep 5
This section ensures that both rsyslog and Fail2Ban services are running and enabled:
It starts and enables rsyslog, which is necessary for logging.
It then starts and enables Fail2Ban.
A 5-second sleep is added to allow Fail2Ban to fully initialize.
echo "Fail2Ban Status:"
sudo systemctl status fail2ban --no-pager || log_error "Failed to get Fail2Ban status"
echo "Fail2Ban SSH Jail Status:"
sudo fail2ban-client status sshd || log_error "Failed to get SSH jail status"
This section checks the status of Fail2Ban:
It displays the overall Fail2Ban service status.
It also shows the status of the SSH-specific jail.
echo "Recent Fail2Ban Logs:"
sudo journalctl -u fail2ban -n 50 --no-pager || log_error "Failed to retrieve Fail2Ban logs"
This command retrieves and displays the most recent 50 log entries for Fail2Ban.
xxxxxxxxxx
echo "Checking Fail2Ban configuration:"
sudo fail2ban-client -t || log_error "Fail2Ban configuration test failed"
echo "Checking if auth.log exists:"
ls -l /var/log/auth.log || log_error "auth.log not found"
echo "Checking permissions of Fail2Ban socket:"
ls -l /var/run/fail2ban/fail2ban.sock || log_error "Fail2Ban socket not found"
echo "Checking rsyslog status:"
sudo systemctl status rsyslog --no-pager || log_error "Failed to get rsyslog status"
This section performs various troubleshooting checks:
Tests the Fail2Ban configuration.
Checks for the existence of the auth log file.
Verifies the Fail2Ban socket permissions.
Checks the status of rsyslog.
xxxxxxxxxx
set +x
echo "Fail2Ban installation and configuration complete."
echo "Please review any ERROR messages above."
This final section:
Disables debugging output.
Prints a completion message and reminds the user to review any error messages.
Let's look at the important configuration parameters set in the jail.local
file:
bantime: Set to 86400 seconds (24 hours). This is the duration for which an IP address is banned.
findtime: Set to 3600 seconds (1 hour). This is the time frame in which Fail2Ban looks for repeated failures.
maxretry: Set to 5. This is the number of failures allowed before banning an IP.
ignoreip: Set to 127.0.0.1/8 ::1
. This prevents Fail2Ban from banning localhost.
backend: Set to systemd
, which is optimal for modern Debian systems.
For the SSH-specific jail:
enabled: Set to true
to activate the SSH jail.
port: Set to ssh
to monitor the default SSH port.
filter: Set to sshd
to use the predefined SSH filter.
logpath: Set to /var/log/auth.log
, which is the standard authentication log file on Debian systems.
Regular Updates: Keep Fail2Ban and your system updated to protect against new threats.
Custom Configuration: The script uses jail.local
for custom settings, which is preferred over editing jail.conf
directly.
Proper Logging: Ensure rsyslog is running and Fail2Ban is monitoring the correct log files.
Ignore Trusted IPs: The script sets ignoreip
to exclude localhost from Fail2Ban rules. Consider adding other trusted IP addresses if necessary.
Adjust Ban Settings: The script sets reasonable defaults, but you may need to adjust bantime
, findtime
, and maxretry
based on your specific security needs.
Use systemd Backend: The script configures Fail2Ban to use the systemd backend, which is more efficient for modern systems.
Comprehensive Error Handling: The script logs errors without stopping execution, allowing for a complete setup process even if minor issues occur.
Thorough Cleanup: Before installation, the script removes any existing Fail2Ban installations and leftover files, ensuring a clean slate.
Status Checks and Troubleshooting: The script includes various status checks and troubleshooting steps, providing valuable information for debugging.
Database Maintenance: Consider adding a cron job to regularly vacuum the Fail2Ban SQLite database:
xxxxxxxxxx
0 2 * * 0 /usr/bin/sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 'vacuum;'
Monitor and Notify: While not included in this script, consider setting up email notifications for Fail2Ban actions.
This comprehensive Fail2Ban setup script for Debian 12 provides a robust foundation for protecting your server against brute-force attacks. It incorporates best practices for 2024, offering improved security, better error handling, and comprehensive troubleshooting capabilities.
Stay safe, and happy server administrating!