Nginx 基础认证与 Fail2ban 防 CC 配置教程

Nginx 基础认证与 Fail2ban 防 CC 配置教程

敏感信息说明:文中域名、IP、账号、密码均为占位符,部署时请替换为实际值。

占位符 含义
admin.example.com 需要保护的站点域名
ADMIN_USER / ADMIN_PASSWORD HTTP 基础认证用户名 / 密码
<ADMIN_IP> 管理员出口 IP(示例 203.0.113.10)
<SERVER_PRIVATE_IP> / <SERVER_PUBLIC_IP> 服务器内网 / 公网 IP
203.0.113.x / 192.0.2.x 文档示例 IP 段(RFC 5737),请替换

一、Nginx HTTP 基础认证(auth_basic)

1.1 背景与原理

管理后台类站点(如 phpLDAPadmin、监控面板)仅靠应用自身登录不够安全。Nginx 可在反向代理前增加一层 HTTP Basic Auth:

1
浏览器 ──HTTPS──▶ nginx(401 要求认证)──认证通过──▶ 后端应用

未认证请求直接被 nginx 拒绝,可有效挡住针对应用漏洞的扫描和爆破。

1.2 前置条件

1
2
3
4
# RHEL/CentOS
yum install -y httpd-tools
# Debian/Ubuntu
apt install -y apache2-utils

1.3 配置步骤

步骤 1:创建密码文件

1
2
3
4
5
# -c 创建新文件;-b 允许命令行传密码(仅限初始化,会留在 shell 历史)
htpasswd -cb /etc/nginx/.htpasswd_admin ADMIN_USER 'ADMIN_PASSWORD'

# 生产环境建议交互式输入(不加 -b)
htpasswd -c /etc/nginx/.htpasswd_admin ADMIN_USER

步骤 2:设置文件权限(关键!)

1
2
chown root:nginx /etc/nginx/.htpasswd_admin   # Debian/Ubuntu 组名为 www-data
chmod 640 /etc/nginx/.htpasswd_admin

⚠️ 踩坑提醒:若权限为 600 且属主 root,nginx worker 读不到文件,带凭据访问会报 500,错误日志出现 open() ... failed (13: Permission denied)。

步骤 3:修改站点配置(如 /etc/nginx/conf.d/admin.example.com.conf)

1
2
3
4
5
6
7
location / {
auth_basic "Restricted - admin.example.com";
auth_basic_user_file /etc/nginx/.htpasswd_admin;

# ...原有 root / proxy_pass 等配置保持不变...
proxy_pass http://127.0.0.1:8080/;
}

💡 修改前先备份(如 cp xxx.conf xxx.conf.bak-YYYYMMDD,文件名中的日期用 date +%Y%m%d 生成)。用 sed 批量插入时注意:被注释的相似行(如 # location / {)也会被匹配到,插入后务必检查全文。

步骤 4:校验并重载

1
nginx -t && systemctl reload nginx

步骤 5:验证

1
2
3
curl -o /dev/null -w '%{http_code}\n' https://admin.example.com/                        # 期望 401
curl -o /dev/null -w '%{http_code}\n' -u 'ADMIN_USER:ADMIN_PASSWORD' https://admin.example.com/ # 期望 200
curl -o /dev/null -w '%{http_code}\n' -u 'ADMIN_USER:wrong' https://admin.example.com/ # 期望 401

1.4 日常运维

1
2
3
htpasswd   /etc/nginx/.htpasswd_admin ADMIN_USER    # 修改密码
htpasswd /etc/nginx/.htpasswd_admin NEW_USER # 新增用户
htpasswd -D /etc/nginx/.htpasswd_admin OLD_USER # 删除用户

1.5 加固建议

  1. 仅走 HTTPS:Basic Auth 仅 Base64 编码,必须配合 TLS
  2. 叠加 IP 白名单(可选):在 location 里加 allow <ADMIN_IP>; deny all;
  3. 认证密码使用强随机密码,不要与应用登录密码相同
  4. 配合 fail2ban 对付暴力破解(见第二部分)

二、Fail2ban nginx-cc 防 CC/请求洪水

2.1 背景与原理

CC 攻击(Layer-7 洪水)通过海量 HTTP 请求耗尽服务资源。Fail2ban 通过分析访问日志识别高频 IP 并调用防火墙封禁:

1
nginx 访问日志 ──▶ filter(正则提取 IP)──▶ jail(频率阈值判定)──▶ action(防火墙封禁)

2.2 关键知识点:fail2ban 会剥离时间戳

这是最容易踩的坑:fail2ban 匹配正则之前,会把日志中的时间戳文本移除。

1
2
原始行:203.0.113.10 - - [24/Oct/2026:10:27:23 +0800] "GET / HTTP/1.1" 200 ...
实际: 203.0.113.10 - - [] "GET / HTTP/1.1" 200 ...

因此日期字段必须写 \[[^\]]*\](* 允许 0 个字符),
不能写 \[[^\]]+\](+ 要求至少 1 个字符)——否则永远匹配不到任何行!

2.3 配置步骤

步骤 1:创建过滤器 /etc/fail2ban/filter.d/nginx-cc.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
# Fail2Ban filter for nginx request-flood (CC / Layer-7).
#
# Counts HTTP request lines in nginx access logs (default "main" log_format).
# Ban threshold is enforced by the jail: maxretry hits within findtime.
#
# NOTE: fail2ban strips the timestamp text before matching, so the log field
# [$time_local] appears as [] to failregex. Use \[[^\]]*\] (star, not plus).

[Definition]

failregex = ^<HOST> - \S+ \[[^\]]*\] "(?:GET|POST|HEAD|PUT|DELETE|OPTIONS|PATCH) [^"]*" \d+

ignoreregex =

说明:<HOST> 是 fail2ban 内置标签,自动提取来源 IP;正则只匹配真实请求行(方法 + 状态码),对应 nginx 默认 main 日志格式 $remote_addr - $remote_user [$time_local] "$request" $status ...。

步骤 2:创建 jail /etc/fail2ban/jail.d/nginx-cc.local

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[nginx-cc]
filter = nginx-cc
enabled = true
port = http,https
logpath = /var/log/nginx/*access.log

# --- 阈值(按流量特征调整)---
findtime = 60 # 统计窗口 60 秒
maxretry = 300 # 窗口内超过 300 次请求(约 5 req/s)判定为洪水
bantime = 24h # 封禁 24 小时

# --- 白名单(务必包含自己和服务器自身 IP,防止自封)---
ignoreip = 127.0.0.1/8 ::1 <SERVER_PRIVATE_IP> <SERVER_PUBLIC_IP> <ADMIN_IP>

# --- 封禁动作 ---
banaction = firewallcmd-ipset # firewalld 环境;纯 iptables 可用 iptables-multiport
action = %(action_)s

⚠️ 注意:

  1. 拼写务必正确(logpath、filter、maxretry),写错会空转——不报错但不生效。用 fail2ban-client status nginx-cc 看 File list 是否非空即可验证。
  2. ignoreip 是保命项,管理员 IP 变更时记得同步。
  3. glob *access.log 覆盖所有 vhost 日志;也可写多行 logpath 显式列出。

步骤 3:用 fail2ban-regex 验证(生效前必做)

1
2
fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-cc.conf
# 期望:Lines: N lines, 0 ignored, N-2 matched, 2 missed
  • matched 应占绝大多数;若为 0,按 2.2 节检查时间戳问题
  • 若正则几乎匹配所有行且 maxretry 很小(如 5),会误封正常用户——阈值必须按请求速率设计

步骤 4:重载并验证

1
2
3
fail2ban-client reload
fail2ban-client status nginx-cc # File list 应非空
fail2ban-client get nginx-cc ignoreip # 检查白名单

2.4 阈值调优参考

站点类型 findtime maxretry 说明
管理后台(低频) 60 100 正常人 1-2 req/s 以内
普通企业站 60 300 约 5 req/s
API/高频服务 60 600+ 结合 limit_req 更稳妥

2.5 日常运维命令

1
2
3
4
5
fail2ban-client status nginx-cc                       # 查看已封 IP、失败计数
fail2ban-client set nginx-cc unbanip 203.0.113.66 # 解封指定 IP
fail2ban-client set nginx-cc addignoreip 203.0.113.20 # 临时加白
fail2ban-client set nginx-cc bantime 12h # 调整封禁时长
fail2ban-regex -v LOG FILTER # 调试正则匹配情况

2.6 常见问题排查

现象 可能原因 解决办法
File list 为空 logpath 拼写错误/路径不存在 修正拼写,确认日志存在
Total failed 恒为 0 正则匹配不到(多为时间戳问题) fail2ban-regex 实测,检查 \[[^\]]*\]
正常用户被误封 正则过宽 + 阈值过低 收紧正则、调大 maxretry
解封后又被封 持续触发阈值 先 addignoreip 再排查流量
封禁不生效 banaction 与防火墙不匹配 firewalld 用 firewallcmd-ipset

2.7 局限性与补充

fail2ban 只能防单 IP 高频请求,分布式低速率 CC 防不住。补充手段:nginx limit_req/limit_conn 限速限并发、CDN/WAF 云端清洗、后端服务自身限流。


附:配置文件速查

文件 作用
/etc/nginx/.htpasswd_admin 基础认证密码文件
/etc/nginx/conf.d/*.conf 站点配置(auth_basic 写在这里)
/etc/fail2ban/filter.d/nginx-cc.conf fail2ban 匹配规则
/etc/fail2ban/jail.d/nginx-cc.local fail2ban 封禁策略
/var/log/nginx/*access.log nginx 访问日志
/var/log/fail2ban.log fail2ban 运行日志

Nginx 基础认证与 Fail2ban 防 CC 配置教程
https://ywmy.xyz/2026/10/24/Nginx-基础认证与-Fail2ban-防-CC-配置教程/
作者
Ian & Doudou
发布于
2026年10月24日
许可协议