Fail2ban Installation และ Configuration — ป้องกัน Brute Force บน Linux

Fail2ban เป็นเครื่องมือ Intrusion Prevention ที่อ่าน Log ของ Service ต่าง ๆ แล้ว Block IP ที่พยายาม Login ผิดหลายครั้งโดยอัตโนมัติผ่าน iptables หรือ nftables ใช้ป้องกัน Brute Force Attack บน SSH, Nginx, Apache, FTP, Mail Server และ Service อื่น ๆ ที่มี Log รูปแบบที่ตรวจสอบได้

บทความนี้อธิบายการติดตั้งและตั้งค่า Fail2ban ตั้งแต่ Concept พื้นฐาน (Jail, Filter, Action), การตั้งค่า jail.local สำหรับ SSH และ Web Server, การ Ban/Unban IP, การ Monitor สถานะ, จนถึงการสร้าง Custom Filter สำหรับ Application ที่ไม่มี Built-in Filter

ติดตั้ง Fail2ban

# Ubuntu/Debian
sudo apt update
sudo apt install fail2ban

# RHEL/Rocky/AlmaLinux (ต้องเปิด EPEL ก่อน)
sudo dnf install epel-release
sudo dnf install fail2ban

# เปิดใช้งานและตรวจสอบ
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

# ตรวจสอบ Version
fail2ban-client --version

โครงสร้างไฟล์ Config

Fail2ban แยก Config เป็น 2 ชั้น: ไฟล์ .conf เป็น Default ที่ห้ามแก้ไข และไฟล์ .local ที่ Override ค่าจาก .conf — ควรแก้ไขเฉพาะไฟล์ .local เพื่อไม่ให้การอัพเดต Package ทับค่าที่ตั้งไว้

# โครงสร้างไดเรกทอรี
/etc/fail2ban/
├── fail2ban.conf          # Config หลัก (ห้ามแก้)
├── fail2ban.local         # Override fail2ban.conf (สร้างเอง)
├── jail.conf              # Jail definitions ทั้งหมด (ห้ามแก้)
├── jail.local             # Override jail.conf (สร้างเอง ← แก้ที่นี่)
├── filter.d/              # Filter ทุกตัว
│   ├── sshd.conf
│   ├── nginx-http-auth.conf
│   ├── apache-auth.conf
│   └── ...
└── action.d/              # Action ทุกตัว
    ├── iptables.conf
    ├── iptables-multiport.conf
    ├── sendmail.conf
    └── ...

# สร้าง jail.local จาก template
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Concept: Jail, Filter, และ Action

Fail2ban ทำงานโดยใช้ 3 ส่วนหลัก ได้แก่ Jail (กลุ่มของ Rule สำหรับ Service หนึ่ง), Filter (Regex ที่ Match กับ Log), และ Action (สิ่งที่ทำเมื่อ Match ครบ Threshold)

# โครงสร้าง Jail (ใน jail.local)
[ssh-custom]
enabled  = true
port     = ssh                  # Port ที่จะ Block
filter   = sshd                 # ชื่อ Filter ใน filter.d/
logpath  = /var/log/auth.log    # Log ที่ Fail2ban อ่าน
maxretry = 5                    # ครั้งที่ผิดก่อน Ban
findtime = 600                  # Window เวลา (วินาที) นับความผิด
bantime  = 3600                 # เวลา Ban (วินาที, -1 = ถาวร)
action   = iptables-multiport   # Action ที่ใช้

# findtime=600 maxretry=5 หมายความว่า:
# ถ้ามี 5 ครั้งผิดใน 10 นาที → Ban 1 ชั่วโมง

ตั้งค่า jail.local — SSH และ Web Server

# /etc/fail2ban/jail.local
# ตั้งค่า Default ที่ใช้กับทุก Jail

[DEFAULT]
# Whitelist IP ที่ไม่ให้ Ban เด็ดขาด
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

# ค่า Default สำหรับทุก Jail
bantime  = 3600       # Ban 1 ชั่วโมง
findtime = 600        # นับใน 10 นาที
maxretry = 5          # หลัง 5 ครั้งผิด

# Backend สำหรับอ่าน Log
backend = auto        # auto เลือก systemd, gamin, polling ตามที่มี

# Action เมื่อ Ban
banaction = iptables-multiport

# ส่ง Email แจ้งเตือนเมื่อ Ban (ต้องมี sendmail/postfix)
# destemail = [email protected]
# sendername = Fail2ban
# action = %(action_mwl)s   # Ban + Email พร้อม Log

[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = %(sshd_log)s    # ใช้ Variable จาก jail.conf
backend  = %(sshd_backend)s
maxretry = 3
bantime  = 86400           # Ban SSH 24 ชั่วโมง
# /etc/fail2ban/jail.local (ต่อ) — Web Server Jails

[nginx-http-auth]
enabled  = true
port     = http,https
filter   = nginx-http-auth
logpath  = /var/log/nginx/error.log
maxretry = 5

[nginx-limit-req]
enabled  = true
port     = http,https
filter   = nginx-limit-req
logpath  = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime  = 600

[nginx-botsearch]
enabled  = true
port     = http,https
filter   = nginx-botsearch
logpath  = /var/log/nginx/access.log
maxretry = 2
findtime = 3600
bantime  = 86400

[apache-auth]
enabled  = true
port     = http,https
filter   = apache-auth
logpath  = /var/log/apache2/*error.log
maxretry = 5
# Reload Fail2ban หลังแก้ไข Config
sudo fail2ban-client reload

# หรือ Restart
sudo systemctl restart fail2ban

# ตรวจสอบว่า Jail โหลดสำเร็จ
sudo fail2ban-client status

Monitor และจัดการ Jail ด้วย fail2ban-client

# ดู Status ของ Fail2ban ทั้งหมด
sudo fail2ban-client status

# ดู Status ของ Jail เฉพาะ
sudo fail2ban-client status sshd

# ตัวอย่าง Output:
# Status for the jail: sshd
# |- Filter
# |  |- Currently failed: 2
# |  |- Total failed:     47
# |  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
# `- Actions
#    |- Currently banned: 3
#    |- Total banned:     12
#    `- Banned IP list: 203.0.113.1 203.0.113.2 198.51.100.5

# ดู IP ที่ถูก Ban ทั้งหมดในทุก Jail
sudo fail2ban-client banned

# ดู Log แบบ Realtime
sudo tail -f /var/log/fail2ban.log
# Ban IP ด้วยตนเอง
sudo fail2ban-client set sshd banip 203.0.113.100

# Unban IP
sudo fail2ban-client set sshd unbanip 203.0.113.100

# Unban IP จากทุก Jail
sudo fail2ban-client unban 203.0.113.100

# ดูว่า IP ถูก Ban อยู่ใน Jail ไหน
sudo fail2ban-client banned 203.0.113.100

# เพิ่ม IP เข้า Ignore List (ไม่ให้ Ban) แบบ Temporary
sudo fail2ban-client set sshd addignoreip 192.168.1.50

# ลบ IP ออกจาก Ignore List
sudo fail2ban-client set sshd delignoreip 192.168.1.50

สร้าง Custom Filter

เมื่อ Application ที่ใช้ไม่มี Filter สำเร็จรูป ต้องสร้าง Filter เองโดยเขียน Regex ที่ Match กับ Log รูปแบบที่ต้องการตรวจจับ

# ตัวอย่าง Log ที่ต้องการ Detect:
# 2026-04-17 00:15:32 [ERROR] Login failed for user 'admin' from 203.0.113.5
# 2026-04-17 00:15:45 [ERROR] Login failed for user 'root' from 203.0.113.5

# สร้าง Filter: /etc/fail2ban/filter.d/myapp-auth.conf
[Definition]
# failregex: Regex ที่ Match กับ Log ที่ถือว่าเป็น Failure
# <HOST> คือ Placeholder สำหรับ IP Address
failregex = \[ERROR\] Login failed for user .+ from <HOST>$

# ignoreregex: Log ที่ Match แต่ให้ข้ามไป (ไม่นับเป็น Failure)
ignoreregex =
# ทดสอบ Filter กับ Log จริง (fail2ban-regex)
sudo fail2ban-regex /var/log/myapp/auth.log /etc/fail2ban/filter.d/myapp-auth.conf

# ตัวอย่าง Output:
# Running tests
# =============
# Use   failregex filter file : myapp-auth, basedir: /etc/fail2ban
# Use      log file : /var/log/myapp/auth.log
# Results
# =======
# Failregex: 15 total
#   |  #) [# of hits] regular expression
#   |  1) [15] \[ERROR\] Login failed ...
# Ignoreregex: 0 total
# Date template hits:
#   |  ...
# Lines: 1253 lines, 0 ignored, 15 matched, 1238 missed

# ทดสอบกับ String โดยตรง (ไม่ต้องมี Log File)
echo '2026-04-17 00:15:32 [ERROR] Login failed for user admin from 203.0.113.5' \
    | fail2ban-regex - /etc/fail2ban/filter.d/myapp-auth.conf
# เพิ่ม Jail ใน jail.local สำหรับ Custom Filter
# /etc/fail2ban/jail.local

[myapp-auth]
enabled  = true
port     = 8080
filter   = myapp-auth
logpath  = /var/log/myapp/auth.log
maxretry = 5
findtime = 300
bantime  = 3600

# Reload
sudo fail2ban-client reload

WordPress Brute Force Protection

# Filter สำหรับ WordPress Login Brute Force
# /etc/fail2ban/filter.d/wordpress-auth.conf

[Definition]
failregex = ^<HOST> .* "POST .*wp-login\.php

# Jail สำหรับ WordPress (ใน jail.local)
[wordpress-auth]
enabled   = true
port      = http,https
filter    = wordpress-auth
logpath   = /var/log/nginx/access.log
maxretry  = 5
findtime  = 60
bantime   = 3600
# Filter สำหรับ WordPress XML-RPC Attack
# /etc/fail2ban/filter.d/wordpress-xmlrpc.conf

[Definition]
failregex = ^<HOST> .* "POST .*xmlrpc\.php

# Jail สำหรับ XML-RPC (ใน jail.local)
[wordpress-xmlrpc]
enabled   = true
port      = http,https
filter    = wordpress-xmlrpc
logpath   = /var/log/nginx/access.log
maxretry  = 2
findtime  = 60
bantime   = 86400    # Ban 24 ชั่วโมง (ร้ายแรงกว่า login)

Incremental Bantime ด้วย bantime.increment

Fail2ban รองรับการเพิ่ม Ban Time ทวีคูณทุกครั้งที่ถูก Ban ซ้ำ ช่วยขับไล่ผู้โจมตีที่ไม่ยอมหยุดได้ดีกว่า Bantime คงที่

# /etc/fail2ban/jail.local — ตั้งค่า Incremental Bantime
[DEFAULT]
# เปิด Incremental
bantime.increment = true

# Multiplier: แต่ละครั้งที่ Ban ซ้ำ เพิ่ม x1, x5, x30, x60, x24h, x48h, ...
bantime.multipliers = 1 5 30 60 300 720 1440 2880

# Base bantime (วินาที) ใช้กับ multiplier
bantime  = 3600

# ผลลัพธ์:
# Ban ครั้งที่ 1: 1h
# Ban ครั้งที่ 2: 5h
# Ban ครั้งที่ 3: 30h
# Ban ครั้งที่ 4: 60h
# ...จนถึง 2880h = 4 เดือน

# ตรวจสอบว่า IP ถูก Ban กี่ครั้ง
sudo fail2ban-client get sshd banip --with-time

Persistent Ban (Ban ถาวรข้ามการ Restart)

# ตั้งค่า Database เพื่อเก็บ Ban History (Persistent)
# /etc/fail2ban/fail2ban.local

[Definition]
# เปิดใช้ DB
dbfile = /var/lib/fail2ban/fail2ban.sqlite3

# เก็บ Ban History ไว้กี่วัน (0 = ไม่เก็บ)
dbpurgeage = 1d    # ล้าง History เก่ากว่า 1 วัน

# ตรวจสอบ DB ว่ามี IP อะไรบ้าง
sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 \
    "SELECT ip, jail, timeofban, bantime FROM bips ORDER BY timeofban DESC LIMIT 20;"

ตรวจสอบ Log และ Debug

# ดู Log ของ Fail2ban
sudo tail -f /var/log/fail2ban.log

# ตัวอย่าง Log:
# 2026-04-17 00:10:01,234 fail2ban.filter [INFO] [sshd] Found 203.0.113.5
# 2026-04-17 00:10:05,789 fail2ban.filter [INFO] [sshd] Found 203.0.113.5
# 2026-04-17 00:10:10,012 fail2ban.actions [NOTICE] [sshd] Ban 203.0.113.5
# 2026-04-17 01:10:10,012 fail2ban.actions [NOTICE] [sshd] Unban 203.0.113.5

# เปิด Debug Mode ชั่วคราว
sudo fail2ban-client set loglevel DEBUG

# ดู Loglevel ปัจจุบัน
sudo fail2ban-client get loglevel

# ตรวจสอบ Rule ใน iptables ที่ Fail2ban เพิ่มไว้
sudo iptables -n -L f2b-sshd
sudo iptables -n -L | grep -A 10 fail2ban

Script ตรวจสอบ Fail2ban

#!/bin/bash
# /usr/local/bin/fail2ban-report.sh
# สรุปสถานะ Fail2ban และ IP ที่ถูก Ban

echo "=== Fail2ban Status Report ==="
echo "Date: $(date)"
echo ""

# ตรวจสอบว่า Service ทำงานอยู่
if ! systemctl is-active --quiet fail2ban; then
    echo "❌ Fail2ban is NOT running!"
    exit 1
fi
echo "✅ Fail2ban is running"
echo ""

# สรุป Jail ทั้งหมด
echo "=== Jail Summary ==="
sudo fail2ban-client status 2>/dev/null | grep "Jail list" | sed 's/.*Jail list:\s*//' | tr ',' '\n' | while read jail; do
    jail=$(echo "$jail" | xargs)
    [ -z "$jail" ] && continue
    banned=$(sudo fail2ban-client status "$jail" 2>/dev/null | grep "Currently banned" | awk '{print $NF}')
    total=$(sudo fail2ban-client status "$jail" 2>/dev/null | grep "Total banned" | awk '{print $NF}')
    echo "  [$jail] Currently banned: ${banned:-0}, Total: ${total:-0}"
done

echo ""

# IP ที่ถูก Ban ทั้งหมด
echo "=== Currently Banned IPs ==="
sudo fail2ban-client banned 2>/dev/null | grep -oP '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | sort -u | while read ip; do
    echo "  $ip"
done

echo ""
echo "=== Done ==="

สรุป

Fail2ban ทำงานโดยอ่าน Log และ Ban IP ที่มีความผิดพลาดเกิน Threshold ที่กำหนดผ่าน iptables การตั้งค่าที่สำคัญคือแก้ไขเฉพาะ jail.local (ไม่แก้ jail.conf) กำหนด ignoreip สำหรับ IP ที่เชื่อถือได้ และตั้ง maxretry/findtime/bantime ให้เหมาะกับแต่ละ Service การใช้ bantime.increment ช่วยให้ Ban Time เพิ่มขึ้นทวีคูณสำหรับผู้โจมตีซ้ำ และ fail2ban-regex ช่วย Test Filter ก่อน Deploy จริง

แนะนำบริการ DE

การติดตั้ง Fail2ban บน Server ต้องการสิทธิ์ Root และการเข้าถึง iptables โดยตรง Cloud VPS ของ DE ให้ Root Access เต็มรูปแบบ สามารถติดตั้ง Fail2ban ตั้งค่า Jail สำหรับทุก Service และ Monitor การโจมตีได้แบบ Real-time เหมาะสำหรับผู้ที่ต้องการป้องกัน Server จาก Brute Force Attack

สำหรับผู้ที่ต้องการโฮสต์เว็บไซต์โดยมีระบบป้องกันพร้อมใช้ Cloud Hosting ของ DE มีระบบป้องกัน Brute Force ที่ตั้งค่าไว้แล้วในระดับ Infrastructure เหมาะสำหรับผู้ที่ต้องการความปลอดภัยโดยไม่ต้องจัดการ iptables เอง