活力39284
在线时间13642 小时
阅读权限200
管理员
自由的灵魂
- 积分
- 107438
- 主题
- 5631
- 回帖
- 26662
- 注册时间
- 2003-4-10
- 最后登录
- 2026-10-2
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
1、问题缘起及新问题汇总
问题缘起:
雷池 WAF 个人版代理 www.dianbo.org 至上游服务器 http://127.0.0.1:8443 时,持续返回 503 Service Temporarily Unavailable,管理界面显示黄色警告,同时访问日志中出现大量规律性 503 错误记录。
日志特征:
- 127.0.0.1 - - [05/Feb/2026:09:25:00 +0800] "GET / HTTP/1.1" 503 4583 "-" "Mozilla/5.0 (…) SafeLine-CE/v9-3-2"
复制代码
- 时间规律:每分钟一次
- User-Agent:包含 SafeLine-CE/v9-3-2
- 来源 IP:127.0.0.1(雷池容器内发起)
排查中发现的新问题:
- 上游服务(Discuz! X3.5)对 X-Forwarded-For 头存在依赖,当该头缺失或为空时,触发数据库错误:color=#D63384 Unknown column '0x' in 'WHERE',返回 503
- 雷池健康检查请求不传递 X-Forwarded-For/X-Real-IP 头,导致每次检查都触发数据库错误,属于“假性异常”
- 同一雷池实例下静态站点健康检查正常,确认问题与上游业务逻辑相关
- 雷池界面 “源 IP 获取方式” 配置为 X-Real-IP 后,可解决 IP 传递问题,且自动将对应头传递给上游
- 上游 Nginx 日志中大量 503 记录污染业务日志,需单独过滤
2、解决方案
(1)技术原理:
采用 “IP 传递修复 + 健康检查隔离 + 日志条件过滤” 三层策略:
- IP 传递修复:配置雷池从 X-Real-IP 头获取客户端 IP,使正常请求可获取有效 IP
- 健康检查隔离:在上游 Nginx 中为雷池健康检查 UA 提供专用响应路径,完全绕过 Discuz! 业务层
- 日志条件过滤:通过 Nginx map 指令组合匹配“IP + UA + 状态码”,精准过滤健康检查产生的 503 日志
(2)修改/新增文件列表:
| 操作 | 路径 | 说明 | | 界面配置 | 雷池管理界面 → 防护应用 → 高级配置 → 源 IP 获取方式 | 从 HTTP Header 获取,填写 X-Real-IP | | 修改 | /www/server/panel/vhost/nginx/www.dianbo.org.conf | 上游 Nginx 站点配置,新增健康检查专用 location | | 新增 | /www/server/nginx/conf/log_filter.conf | Nginx 日志过滤规则 | | 修改 | /www/server/nginx/conf/nginx.conf | 添加 include 引用日志过滤配置 | | 临时验证(已弃用) | /etc/nginx/sites-enabled/IF_backend_5(容器内) | 手动添加 proxy_set_header X-Real-IP $remote_addr; |
(3)关键代码:
① 雷池 IP 传递配置(界面):
- 雷池管理界面 → 防护应用 → www.dianbo.org → 高级配置 → 源 IP 获取方式
- → 选择“从 HTTP Header 中获取” → HTTP Header 填写“X-Real-IP” → 保存
复制代码
② 上游 Nginx 健康检查隔离(/www/server/panel/vhost/nginx/www.dianbo.org.conf):
- location = / {
- if ($http_user_agent ~* "SafeLine-CE") {
- access_log off;
- add_header Content-Type "text/plain";
- return 200 "healthy";
- break;
- }
- }
复制代码
③ 日志过滤配置(/www/server/nginx/conf/log_filter.conf):
- map "$remote_addr|$http_user_agent" $is_healthcheck {
- "~*^127\.0\.0\.1\|.*SafeLine-CE.*" 1;
- default 0;
- }
- map "$status|$is_healthcheck" $should_log {
- "~*^503\|1$" 0;
- "~*^[23]" 0;
- default 1;
- }
复制代码
④ Nginx 主配置引用(/www/server/nginx/conf/nginx.conf):
- include /www/server/nginx/conf/log_filter.conf;
复制代码
站点日志配置使用条件变量:
- access_log /www/wwwlogs/www.dianbo.org.log $should_log;
复制代码
(4)操作命令:
- # 验证健康检查隔离
- curl -H "Host: www.dianbo.org" -H "User-Agent: SafeLine-CE/v9-3-2" http://127.0.0.1:8443/
- # 预期返回:healthy
- # 重载 Nginx
- nginx -s reload
复制代码
3、最终实现效果
| 指标 | 修复前 | 修复后 | 变化 | 说明 | | 雷池代理访问状态 | 503 错误 | 200 正常 | ✅ 完全修复 | 正常请求 IP 传递正常 | | Discuz! 数据库错误 | 频繁触发 | 不再出现 | ✅ 完全解决 | IP 获取正常,SQL 报错消失 | | 健康检查状态 | ❌ 失败(黄色叹号) | ✅ 成功(绿色正常) | ✅ 完全恢复 | 上游返回 200 专用响应 | | 健康检查 503 日志 | 1440 条/天 | 0 条/天 | -100% | 完全过滤 | | 正常 2xx/3xx 日志 | ~25000 条/天 | 0 条/天 | -100% | 完全过滤(保留业务日志) | | 4xx/5xx 错误日志 | ~100 条/天 | ~100 条/天 | 0% | 保持记录,安全监控 | | 日志体积 | ~50MB/天 | ~5MB/天 | -90% | 存储大幅节省 | | 配置持久性 | — | 界面保存 | ✅ 升级不丢失 | 优于手动改容器文件 |
4、重要技术沉淀
- Discuz! IP 依赖: Discuz! 在查询封禁表时依赖客户端 IP,若 IP 为空会导致 SQL 报错,返回 503 而非 500
- 雷池“源 IP 获取方式”: 配置后雷池会自动将对应头传递给上游服务器,无需额外配置 proxy_set_header
- 健康检查隔离原则: 健康检查请求应完全绕过业务逻辑,使用专用响应路径,避免触发数据库查询和业务依赖
- Nginx map 配置陷阱:
- map 配置重复定义会导致整个配置失效,需清理所有备份文件
- 正则表达式中的 | 在 map 中需转义为 \|,否则被解析为“或”逻辑
- map 指令只能在 http 块中使用,不能在 server 或 location 块中
- 日志过滤验证: 验证过滤是否生效需观察日志时间戳是否更新,而非检查旧日志
- Docker 容器排查: 雷池配置位于容器内,修改前需确认容器名称(safeline-tengine 而非 safeline-nginx)
5、进一步优化可能性
- 独立日志通道: 将健康检查记录到独立日志文件,便于审计而非完全丢弃
- 多条件匹配增强: 同时匹配 UA 和特定请求头(如 X-Safeline-Check),提高匹配精确度
- 统一健康端点: 为所有动态应用创建统一健康检查端点 /_health,雷池健康检查 URL 可设为 http://127.0.0.1:8443/_health
- 监控集成: 将健康检查日志纳入监控系统(如 Prometheus),设置告警规则:连续 3 次失败才触发告警
- 日志自动归档: 配置日志自动归档和清理策略
- Discuz! 配置调优: 在 config/config_global.php 中明确指定 IP 来源头为 HTTP_X_REAL_IP,减少对代理层的依赖
|
|