“How to Reduce and Maintain fail2ban SQLite Database Size Under 500MB”


1 views

html

Solving fail2ban's Oversized SQLite Database Issue

Many sysadmins encounter unexpected disk usage from fail2ban's SQLite database at /var/lib/fail2ban/fail2ban.sqlite3. The database typically grows from:

  • Excessive banned IP records
  • Long default ban durations
  • Lack of automatic purging
  • Verbose logging configurations

First, let's shrink the existing database. Connect to the SQLite database and clean old records:

sqlite3 /var/lib/fail2ban/fail2ban.sqlite3
-- Check current size
PRAGMA page_count * PRAGMA page_size;

-- Remove banned IPs older than 30 days
DELETE FROM bans WHERE timeofban < strftime('%s', 'now', '-30 days');

-- Compact the database
VACUUM;

-- Verify new size
PRAGMA page_count * PRAGMA page_size;
.exit

Add these settings to /etc/fail2ban/fail2ban.local:

[Definition]
# Auto-purge bans after 7 days
dbpurgeage = 604800

# Reduce log verbosity
loglevel = INFO

# Limit max bans retained
maxretry = 3

Create a cron job at /etc/cron.weekly/fail2ban-maintenance:

#!/bin/bash
# Compact fail2ban database weekly
sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "VACUUM;"
# Restart service to apply changes
systemctl restart fail2ban

For high-traffic servers, consider moving to MySQL:

[DEFAULT]
# In /etc/fail2ban/fail2ban.local
dbengine = mysql
dbhost = localhost
dbuser = fail2ban
dbpassword = your_secure_password
dbname = fail2ban

Add this to your monitoring system (e.g., Nagios or Zabbix):

#!/bin/bash
DBSIZE=$(du -b /var/lib/fail2ban/fail2ban.sqlite3 | awk '{print $1}')
WARN=300000000 # 300MB
CRIT=500000000 # 500MB

if [ "$DBSIZE" -gt "$CRIT" ]; then
  echo "CRITICAL: fail2ban db $DBSIZE bytes"
  exit 2
elif [ "$DBSIZE" -gt "$WARN" ]; then
  echo "WARNING: fail2ban db $DBSIZE bytes"
  exit 1
else
  echo "OK: fail2ban db $DBSIZE bytes"
  exit 0
fi

When managing server security with fail2ban, many administrators encounter an unexpectedly large SQLite database file (/var/lib/fail2ban/fail2ban.sqlite3). The database can grow beyond 500MB, causing issues with:

  • Backup failures due to size limitations
  • Increased disk I/O operations
  • Potential performance degradation

fail2ban's SQLite database primarily stores:

1. Ban records (including IPs, timestamps, and jails)
2. Persistent bans (if configured)
3. Long-term statistical data

To quickly reduce the database size, you have several options:

Option 1: Purge Old Records

# First, create a backup
sudo cp /var/lib/fail2ban/fail2ban.sqlite3 /var/lib/fail2ban/fail2ban.sqlite3.bak

# Then connect to the SQLite database
sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3

-- Delete records older than 30 days
DELETE FROM bans WHERE timeofban < strftime('%s', 'now', '-30 days');

-- Vacuum the database to reclaim space
VACUUM;

-- Exit SQLite
.quit

Option 2: Reset the Database Completely

sudo systemctl stop fail2ban
sudo rm /var/lib/fail2ban/fail2ban.sqlite3
sudo systemctl start fail2ban

Configuration Adjustment

Add these settings to your /etc/fail2ban/jail.local:

[DEFAULT]
# Automatically purge bans after 7 days
bantime = 7d

# Enable database purging
dbpurgeage = 7d

Regular Maintenance Script

Create a cron job to regularly clean the database:

#!/bin/bash
# /usr/local/bin/fail2ban_db_clean.sh

DB_PATH="/var/lib/fail2ban/fail2ban.sqlite3"
KEEP_DAYS=14

sqlite3 "$DB_PATH" "DELETE FROM bans WHERE timeofban < strftime('%s', 'now', '-$KEEP_DAYS days');"
sqlite3 "$DB_PATH" "VACUUM;"

# Add to cron (runs weekly)
# 0 3 * * 0 /usr/local/bin/fail2ban_db_clean.sh

Using fail2ban-client

For newer versions of fail2ban, you can use built-in commands:

# List all banned IPs
sudo fail2ban-client status sshd

# Unban specific IPs
sudo fail2ban-client set sshd unbanip 192.168.1.100

Database Optimization

Consider these SQLite performance settings if you need to keep historical data:

PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = -2000;  # 2MB cache

Add this to your monitoring system to alert when the database grows too large:

#!/bin/bash
# /usr/local/bin/check_fail2ban_db.sh

MAX_SIZE_MB=500
DB_SIZE=$(du -m /var/lib/fail2ban/fail2ban.sqlite3 | awk '{print $1}')

if [ "$DB_SIZE" -gt "$MAX_SIZE_MB" ]; then
    echo "CRITICAL: fail2ban database size is ${DB_SIZE}MB"
    exit 2
else
    echo "OK: fail2ban database size is ${DB_SIZE}MB"
    exit 0
fi