自定义fail2ban规则拦截跨境扫描IP:实战

服务器日志里经常出现大量来自境外IP的端口扫描或暴力破解尝试?
默认的fail2ban规则只能根据访问频率封禁,但无法区分地域。
本文教你通过自定义fail2ban的filter和action,搭配GeoIP数据库,自动拦截所有匹配扫描模式的跨境IP,从源头减少无效请求。

适用场景与准备工作

这套方案适合以下场景:你的业务主要面向国内用户,但服务器24小时被海外IP扫端口或测漏洞;
或者你想在fail2ban原有的频率封锁基础上,加一道地域白名单/黑名单。

准备工作清单

  • 一台已安装fail2ban的Linux服务器(CentOS 7+/Ubuntu 18.04+都可以)
  • root或sudo权限
  • 安装geoip-biniptables(iptables通常自带),用于获取IP归属地并执行封禁
# 安装fail2ban(如果未安装)
sudo apt install fail2ban -y         # Debian/Ubuntu
sudo yum install epel-release -y && sudo yum install fail2ban -y   # CentOS

# 安装geoip工具
sudo apt install geoip-bin -y        # 提供geoiplookup命令
# 或从MaxMind下载免费GeoLite2库,但简单起见用系统包自带

第一步:编写自定义filter匹配扫描行为

fail2ban通过filter来匹配日志中的“违规”行。
我们创建一个专门识别端口扫描特征的自定义filter,例如匹配nmap扫描、大量SYN请求或零窗口扫描。

sudo vim /etc/fail2ban/filter.d/custom-scan.conf

写入以下内容(以匹配ssh日志中“Failed password”为例,但扫描往往不一定是密码错误,也可能是连接超时。
这里用更通用的[sshd]默认filter?
不,我们单独写一个:)

[Definition]
failregex = ^%(__prefix_line)sConnection from  port \d+ on .* invalid$
            ^%(__prefix_line)sDid not receive identification string from $
            ^%(__prefix_line)sBad protocol version identification .* from $
ignoreregex =

这样匹配的是连接时未发送识别字符串、错误协议版本等典型扫描特征。
你可以根据实际日志调整正则。

第二步:编写自定义action——封禁前先判断地域

默认action直接封IP。
我们要改造它:在封禁前检查IP来源,如果是境内IP则跳过(避免误封),境外IP才加入黑名单。

创建自定义action文件:

sudo vim /etc/fail2ban/action.d/custom-block.conf

内容如下(使用iptables + ipset,并调用geoiplookup判断):

[Definition]
actionstart = ipset create fail2ban-custom hash:ip timeout 86400 2>/dev/null || true
              iptables -I INPUT -m set --match-set fail2ban-custom src -j DROP

actionban = if [ "$(geoiplookup  | grep -c 'Country: CN')" -eq 0 ]; then
              ipset add fail2ban-custom 
            fi

actionunban = ipset del fail2ban-custom 

注意:这里假设geoiplookup输出包含“Country: CN”表示中国IP;
如果不是中国IP则加入ipset。
如果你的服务器面向全球,请根据实际需求调整。

第三步:在jail.local中启用自定义规则

编辑/etc/fail2ban/jail.local(如果没有则创建):

sudo vim /etc/fail2ban/jail.local

追加以下配置:

[custom-scan]
enabled  = true
filter   = custom-scan
logpath  = /var/log/auth.log
          /var/log/secure
maxretry = 3
findtime = 300
bantime  = 86400
action   = custom-block
           %(action_mwl)s    # 同时发送邮件告警(可选)

注意:logpath请根据你的系统日志位置调整(CentOS用/var/log/secure,Ubuntu用/var/log/auth.log)。
如果还要监控其他服务(如nginx),可以加多条logpath。

第四步:重启fail2ban并验证效果

sudo systemctl restart fail2ban
sudo fail2ban-client status custom-scan

如果看到“Status for the jail: custom-scan”且“Currently banned: X”不为0,说明已生效。
你也可以手动模拟扫描:

# 从境外服务器尝试ssh连接失败几次
ssh invalid@your-server
# 然后查看fail2ban日志
sudo tail -f /var/log/fail2ban.log

当匹配到filter中的规则时,会看到类似“Ban <境外IP>”的行。
注意:这里的封禁是由自定义action执行的,只有境外IP才会被加入ipset。

避坑指南

  • GeoIP数据库不完整:系统自带的geoiplookup可能不准确,特别是IPv6。建议使用MaxMind的GeoLite2库,但操作更复杂。初学者先用系统包。
  • 误封国内IP:如果filter匹配过于宽松,国内IP也可能被触发规则。建议先小范围测试,先用findtimemaxretry调松一点,比如5次/5分钟。
  • iptables规则重启丢失:ipset在重启后会被清除,但fail2ban重启时会重新加载actionstart。确保actionstart中的ipset创建失败不会影响。
  • 日志路径不对:自定义filter要匹配的日志,必须写在logpath里。如果监控nginx日志,要额外加logpath。

常见问题FAQ

Q:执行geoiplookup报“No such file or directory”?
A:没安装geoip-bin,或数据库文件缺失。运行sudo apt install geoip-binsudo yum install geoip

Q:如何只拦截非中国IP,同时允许国内IP?
A:上面的action中grep -c 'Country: CN'就是判断中国;要想只拦截非中国,就把if条件改为等于0时封禁。

Q:filter的正则一直匹配不到怎么办?
A:先用fail2ban-regex /var/log/auth.log "你的正则"测试。也可以直接用系统自带的sshd filter,然后单独用action做地域判断。

总结

通过自定义fail2ban filter和action,你可以精确控制封禁策略:只对境外扫描IP执行封锁,避免误伤正常用户。
这套方案适用于所有Linux服务器,且完全开源免费。
如果你发现仍有大量国内IP扫描,可以进一步调整filter或考虑云端WAF。
建议先用一段时间,观察封禁日志,再微调参数。

如果你还想了解fail2ban的更多高级用法(如白名单、ipset持久化),欢迎继续翻阅本站相关文章。

分享到:
上一篇
容器隔离多站点彻底解决防关联需求:Docker实战教程
下一篇
AI中转站日志审计溯源恶意调用记录
1
系统公告

机房迁移升级通知

尊敬的用户: IP 段 103.23.148.x、156.224.29.x 原香港一区线路波动、攻击频繁,平台定于 7 月 5 日凌晨分批迁移至香港 GIA 机房,硬件升级 AMD 铂金机型。 迁移均在凌晨操作,最大程度降低业务影响,迁移期间服务器临时关机; 升级后配置不降低、费用不涨价,数据默认同步迁移; 迁移后 IP 全部更换,请及时修改域名解析、防火墙白名单; 建议提前备份重要数据,有问题可联系在线客服。 感谢理解与支持! 泽御云科技 2026.06.30
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意