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


12 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