fail2ban 服务器安全防护实战指南

作者:

!fail2ban

作为一名运维工程师,你一定遇到过这种情况:服务器日志里密密麻麻的 SSH 登录失败记录,Nginx 访问日志里某个 IP 疯狂扫描你的网站。手动封禁 IP?太累了。iptables 规则写到飞起?治标不治本。

fail2ban 就是为解决这个问题而生的——它能自动分析日志,发现恶意行为后自动封禁 IP,是你服务器安全的第一道防线。

什么是 fail2ban

fail2ban 是一款开源的入侵防护工具,工作原理很简单:

  1. 监控日志文件:实时读取指定日志(如 /var/log/auth.log)
  2. 正则匹配:用预定义的 filter 规则识别失败行为
  3. 计数触发:在指定时间窗口内达到阈值次数
  4. 执行动作:自动调用 iptables/firewalld 封禁 IP

整个过程完全自动化,你只需要配置好规则,剩下的交给它。

为什么选择 fail2ban

市面上安全工具不少,为什么 fail2ban 能成为 Linux 服务器的标配?

特性 fail2ban denyhosts CSF

|——|———-|———–|—–|

支持服务 任意日志 仅 SSH 多种
自定义规则 灵活 有限 复杂
资源占用
社区活跃 活跃 停更 活跃
学习成本 中等

核心优势:fail2ban 不仅能保护 SSH,还能保护 Nginx、Apache、Postfix、Dovecot 等任何能输出日志的服务。

安装与基础配置

安装

`bash

# Ubuntu/Debian

sudo apt update

sudo apt install fail2ban -y

# CentOS/RHEL

sudo yum install epel-release -y

sudo yum install fail2ban -y

# Arch Linux

sudo pacman -S fail2ban

`

安装后启动服务:

`bash

sudo systemctl enable fail2ban

sudo systemctl start fail2ban

`

配置文件结构

fail2ban 的配置文件位于 /etc/fail2ban/

`

/etc/fail2ban/

├── fail2ban.conf # 主配置(日志级别、PID文件等)

├── jail.conf # 默认规则(不要修改!)

├── jail.local # 自定义规则(你改这个)

├── jail.d/ # 额外规则片段

├── filter.d/ # 过滤器规则

├── action.d/ # 动作定义

└── fail2ban.service # systemd 服务文件

`

重要:永远不要直接修改 jail.conf,升级会覆盖。所有自定义配置写在 jail.local

基础配置示例

创建 /etc/fail2ban/jail.local

`ini

[DEFAULT]

# 默认封禁时间(秒),1小时

bantime = 3600

# 检测时间窗口(秒),10分钟

findtime = 600

# 最大失败次数

maxretry = 5

# 使用 firewalld(CentOS 7+)或 iptables

banaction = firewallcmd-ipset

# 忽略本地回环

ignoreip = 127.0.0.1/8 ::1

# 忽略内网IP(根据你的网络调整)

ignoreip = 127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16

[sshd]

enabled = true

port = ssh

filter = sshd

logpath = /var/log/auth.log

maxretry = 3

bantime = 86400

`

这个配置的意思是:SSH 登录失败 3 次,封禁 24 小时。

核心概念详解

Jail(监狱)

Jail 是 fail2ban 的核心概念,代表一个保护规则。每个 jail 定义了:

  • 监控哪个日志(logpath)
  • 用什么规则匹配(filter)
  • 失败几次触发(maxretry)
  • 封禁多久(bantime)
  • 在多长时间内计数(findtime)

Filter(过滤器)

过滤器定义了如何从日志中识别恶意行为。它们是正则表达式文件,位于 /etc/fail2ban/filter.d/

查看 SSH 过滤器:

`bash

cat /etc/fail2ban/filter.d/sshd.conf

`

你会看到类似这样的规则:

`ini

failregex = ^.*Failed password for .* from .*$

^.*Invalid user .* from .*$

^.*Connection closed by authenticating user .* .*[preauth]$

`

是占位符,fail2ban 会自动提取匹配的 IP 地址。

Action(动作)

动作定义了封禁 IP 的方式。默认使用 iptables,常见动作包括:

  • iptables-multiport:在指定端口封禁
  • iptables-allports:封禁所有端口
  • firewallcmd-ipset:使用 firewalld(CentOS 7+)
  • route:通过路由表封禁

你也可以自定义动作,比如发送邮件通知。

SSH 安全防护

SSH 是服务器最常见的攻击目标,也是 fail2ban 最基础的保护场景。

基础 SSH 防护

`ini

[sshd]

enabled = true

port = ssh

filter = sshd

logpath = /var/log/auth.log

maxretry = 3

bantime = 86400

findtime = 600

`

针对暴力破解的强化配置

如果你的服务器暴露在公网,建议更严格:

`ini

[sshd-aggressive]

enabled = true

port = ssh

filter = sshd[mode=aggressive]

logpath = /var/log/auth.log

maxretry = 2

bantime = 604800

findtime = 3600

`

mode=aggressive 会匹配更多恶意行为模式,包括:

  • 密码错误
  • 无效用户
  • Root 登录尝试
  • 暴力破解特征

保护非标准 SSH 端口

如果你改了 SSH 端口(比如 2222):

`ini

[sshd-custom]

enabled = true

port = 2222

filter = sshd

logpath = /var/log/auth.log

maxretry = 3

bantime = 86400

`

Nginx 安全防护

Nginx 是 Web 服务器的主力,也是攻击者的重点目标。

防止暴力破解登录页面

创建过滤器 /etc/fail2ban/filter.d/nginx-auth.conf

`ini

[Definition]

failregex = ^ -.*”(GET|POST).*/login.* HTTP/.*” (401|403) .*$

^ -.*”(GET|POST).*/admin.* HTTP/.*” (401|403) .*$

ignoreregex =

`

配置 jail:

`ini

[nginx-auth]

enabled = true

port = http,https

filter = nginx-auth

logpath = /var/log/nginx/access.log

maxretry = 5

bantime = 3600

findtime = 600

`

防止扫描器和爬虫

创建过滤器 /etc/fail2ban/filter.d/nginx-scan.conf

`ini

[Definition]

failregex = ^ -.*(GET|HEAD) /(wp-admin|wp-login|xmlrpc|phpmyadmin).* HTTP/.*” (404|403) .*$

^ -.*”GET /(env|info|phpinfo|test|shell).* HTTP/.*” (404|403) .*$

ignoreregex =

`

配置 jail:

`ini

[nginx-scan]

enabled = true

port = http,https

filter = nginx-scan

logpath = /var/log/nginx/access.log

maxretry = 10

bantime = 7200

findtime = 3600

`

防止 DDoS 和 CC 攻击

创建过滤器 /etc/fail2ban/filter.d/nginx-req-limit.conf

`ini

[Definition]

failregex = limiting requests, excess: .* by zone .*, client:

ignoreregex =

`

配合 Nginx 的 limit_req_zone 使用:

`nginx

# nginx.conf

http {

limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;

server {

location / {

limit_req zone=req_limit burst=20 nodelay;

}

}

}

`

配置 jail:

`ini

[nginx-req-limit]

enabled = true

port = http,https

filter = nginx-req-limit

logpath = /var/log/nginx/error.log

maxretry = 5

bantime = 3600

findtime = 600

`

防止恶意 User-Agent

创建过滤器 /etc/fail2ban/filter.d/nginx-bad-agent.conf

`ini

[Definition]

failregex = ^ -.*”.*” .* “.*(sqlmap|nikto|nmap|masscan|python-requests|Go-http-client).*”$

ignoreregex =

`

配置 jail:

`ini

[nginx-bad-agent]

enabled = true

port = http,https

filter = nginx-bad-agent

logpath = /var/log/nginx/access.log

maxretry = 1

bantime = 86400

findtime = 86400

`

Apache 安全防护

如果你用的是 Apache,配置方式类似。

防止暴力破解

`ini

[apache-auth]

enabled = true

port = http,https

filter = apache-auth

logpath = /var/log/apache2/error.log

maxretry = 5

bantime = 3600

findtime = 600

`

防止扫描

`ini

[apache-scan]

enabled = true

port = http,https

filter = apache-scan

logpath = /var/log/apache2/access.log

maxretry = 10

bantime = 7200

findtime = 3600

`

邮件服务防护

邮件服务器是垃圾邮件和暴力破解的重灾区。

Postfix 防护

`ini

[postfix]

enabled = true

port = smtp,465,submission

filter = postfix

logpath = /var/log/mail.log

maxretry = 3

bantime = 3600

findtime = 600

[postfix-sasl]

enabled = true

port = smtp,465,submission

filter = postfix-sasl

logpath = /var/log/mail.log

maxretry = 3

bantime = 86400

findtime = 600

`

Dovecot 防护

`ini

[dovecot]

enabled = true

port = pop3,pop3s,imap,imaps

filter = dovecot

logpath = /var/log/mail.log

maxretry = 3

bantime = 3600

findtime = 600

`

进阶配置

自定义过滤器

假设你有一个自定义应用,日志格式如下:

`

2024-01-15 10:30:45 [ERROR] Login failed from 192.168.1.100 – Invalid credentials

`

创建过滤器 /etc/fail2ban/filter.d/myapp.conf

`ini

[Definition]

failregex = ^.*[ERROR] Login failed from – .*$

ignoreregex =

`

测试过滤器:

`bash

fail2ban-regex /var/log/myapp.log /etc/fail2ban/filter.d/myapp.conf

`

递增封禁时间

对于反复攻击的 IP,可以递增封禁时间:

`ini

[recidive]

enabled = true

filter = recidive

logpath = /var/log/fail2ban.log

action = iptables-allports[name=recidive]

bantime = 604800

findtime = 86400

maxretry = 3

`

这个 jail 会监控 fail2ban 自己的日志,如果一个 IP 在 24 小时内被封禁 3 次以上,就封禁 7 天。

邮件通知

配置封禁时发送邮件通知:

`ini

[DEFAULT]

# 在 jail.local 的 [DEFAULT] 部分添加

action = %(action_mwl)s

# action_mwl = ban + 发送邮件 + 包含日志

# action_mw = ban + 发送邮件(不含日志)

# action_ml = ban + 只发日志(不封禁)

`

配置邮件参数 /etc/fail2ban/action.d/mail.conf

`ini

[Definition]

actionstart =

actionstop =

actioncheck =

actionban = printf %%b “Hi,nnThe IP has just been banned by Fail2Ban after attempts against .nnRegards,nFail2Ban” | mail -s “[Fail2Ban] : banned ” your@email.com

actionunban =

`

使用 firewalld(CentOS 7+)

CentOS 7 默认使用 firewalld,需要调整 banaction:

`ini

[DEFAULT]

banaction = firewallcmd-ipset

banaction_allports = firewallcmd-ipset

`

或者使用 rich rules:

`ini

[DEFAULT]

banaction = firewallcmd-rich-rules[actiontype=]

`

使用 nftables

如果你使用 nftables(新版 Linux 推荐):

`ini

[DEFAULT]

banaction = nftables[type=multiport]

banaction_allports = nftables[type=allports]

`

故障排除

查看 fail2ban 状态

`bash

# 查看所有 jail 状态

fail2ban-client status

# 查看特定 jail 状态

fail2ban-client status sshd

# 查看被封禁的 IP

fail2ban-client get sshd banned

# 查看 jail 配置

fail2ban-client get sshd maxretry

fail2ban-client get sshd bantime

`

手动封禁/解封 IP

`bash

# 手动封禁 IP

fail2ban-client set sshd banip 192.168.1.100

# 手动解封 IP

fail2ban-client set sshd unbanip 192.168.1.100

# 查看封禁历史

fail2ban-client get sshd banip –with-time

`

测试过滤器

`bash

# 测试过滤器是否能匹配日志

fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

# 详细输出

fail2ban-regex -v /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

# 测试单行

fail2ban-regex “Failed password for root from 192.168.1.100 port 22 ssh2” /etc/fail2ban/filter.d/sshd.conf

`

常见问题

问题 1:fail2ban 启动失败

`bash

# 查看错误日志

journalctl -u fail2ban -f

# 常见原因:配置文件语法错误

fail2ban-client -t

`

问题 2:IP 被封禁但还能访问

`bash

# 检查 iptables 规则

iptables -L -n | grep f2b

# 检查 firewalld 规则

firewall-cmd –list-all

# 检查日志

tail -f /var/log/fail2ban.log

`

问题 3:误封正常用户

`bash

# 立即解封

fail2ban-client set sshd unbanip 用户IP

# 添加到白名单

# 在 jail.local 的 [DEFAULT] 部分

ignoreip = 127.0.0.1/8 用户IP

`

问题 4:日志轮转后 fail2ban 不工作

`bash

# 创建 logrotate 配置

cat > /etc/logrotate.d/fail2ban << EOF

/var/log/fail2ban.log {

weekly

rotate 4

compress

delaycompress

missingok

notifempty

create 0640 root root

postrotate

fail2ban-client flushlogs > /dev/null 2>&1 || true

endscript

}

EOF

`

调试模式

`bash

# 前台运行,查看详细日志

fail2ban-client -f start

# 或者提高日志级别

fail2ban-client set loglevel 4

`

性能优化

使用 ipset 提升性能

当封禁 IP 数量很多时,iptables 性能会下降。使用 ipset 可以大幅提升:

`ini

[DEFAULT]

banaction = iptables-ipset-proto4

# 或者

banaction = iptables-ipset-proto6

`

调整监控频率

默认 fail2ban 每秒检查一次日志,可以根据服务器负载调整:

`ini

# /etc/fail2ban/fail2ban.conf

[Definition]

# 检查间隔(秒)

dbpurgeage = 86400

`

数据库优化

fail2ban 默认使用 SQLite 存储封禁记录,大量 IP 时可以优化:

`bash

# 查看数据库大小

ls -lh /var/lib/fail2ban/fail2ban.sqlite3

# 清理旧记录

fail2ban-client flushlogs

`

最佳实践

1. 合理设置阈值

  • SSH:maxretry=3, bantime=86400(24小时)
  • Web 登录:maxretry=5, bantime=3600(1小时)
  • API 接口:maxretry=10, bantime=1800(30分钟)

2. 必须设置白名单

`ini

[DEFAULT]

# 至少包含以下 IP

ignoreip = 127.0.0.1/8 ::1 你的管理IP

`

3. 启用持久化

`ini

[DEFAULT]

# 封禁记录持久化到数据库

dbfile = /var/lib/fail2ban/fail2ban.sqlite3

dbpurgeage = 604800

`

4. 定期检查状态

`bash

# 创建监控脚本

cat > /usr/local/bin/fail2ban-status.sh << 'EOF'

#!/bin/bash

echo “=== Fail2Ban Status ===”

fail2ban-client status

echo “”

echo “=== Banned IPs ===”

for jail in $(fail2ban-client status | grep “Jail list” | sed ‘s/.*://;s/,/ /g’); do

echo “Jail: $jail”

fail2ban-client status $jail | grep “Banned IP”

done

EOF

chmod +x /usr/local/bin/fail2ban-status.sh

`

5. 配合其他工具

fail2ban 不是万能的,建议配合:

  • iptables 基础规则:限制连接速率
  • SSH 密钥登录:禁用密码登录
  • VPN:管理端口不对外暴露
  • IDS/IPS:更高级的入侵检测

实战案例

案例 1:保护 WordPress 登录

`ini

# /etc/fail2ban/filter.d/wordpress.conf

[Definition]

failregex = ^ -.*”(GET|POST) /wp-login.php.*$

^ -.*”(GET|POST) /xmlrpc.php.*$

ignoreregex =

# /etc/fail2ban/jail.local

[wordpress]

enabled = true

port = http,https

filter = wordpress

logpath = /var/log/nginx/access.log

maxretry = 5

bantime = 3600

findtime = 600

`

案例 2:保护 GitLab

`ini

# /etc/fail2ban/filter.d/gitlab.conf

[Definition]

failregex = ^ -.*”(GET|POST) /users/sign_in.* HTTP/.*” (401|422) .*$

^ -.*”(GET|POST) /users/auth/.* HTTP/.*” (401|422) .*$

ignoreregex =

[gitlab]

enabled = true

port = http,https

filter = gitlab

logpath = /var/log/gitlab/gitlab-rails/production.log

maxretry = 5

bantime = 3600

findtime = 600

`

案例 3:保护 MySQL

`ini

# /etc/fail2ban/filter.d/mysqld.conf

[Definition]

failregex = ^.*Access denied for user .* from .*$

ignoreregex =

[mysqld]

enabled = true

port = 3306

filter = mysqld

logpath = /var/log/mysql/error.log

maxretry = 3

bantime = 86400

findtime = 600

`

总结

fail2ban 是服务器安全的瑞士军刀,简单但强大。通过合理配置,它可以:

  • 自动封禁恶意 IP,减少人工干预
  • 保护 SSH、Web、邮件等多种服务
  • 灵活的自定义规则适应各种场景
  • 低资源占用,适合各种规模服务器

记住几个关键点:

  1. 永远设置白名单,避免把自己锁在外面
  2. 测试过滤器,确保规则正确匹配
  3. 监控 fail2ban 日志,及时发现问题
  4. 配合其他安全措施,多层防护

安全无小事,fail2ban 只是开始。养成良好的安全习惯,定期更新系统,使用强密码或密钥认证,才能让你的服务器固若金汤。


作者:攀岩者 | 技术总监 | 19年IT全栈实战

精通网络、安全、云计算、容器、数据库、超算,持证 PMP、ITIL、CKA、网络工程师等。主导过多个千万级政务与智慧城市项目,从售前到交付全流程打通。热衷开源,日拱一卒,每天分享技术笔记,陪你从零基础到运维达人。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注