web WAF
OpenResty + Lua WAF + Lua 简单风控统计 + GoAccess / Prometheus / Grafana
my-waf-resty
│
├─ conf/ # nginx.conf + vhost conf
│ ├─ nginx.conf
│ └─ sites-enabled/
│
├─ lua/ # Lua WAF 脚本
│ └─ waf.lua
│
├─ logs/ # access + error logs
│ ├─ access.log
│ └─ error.logsh
docker network create -d bridge nginx-proxy-net创建所需目录
sh
mkdir conf lua logs conf.d ssl www
mkdir -p prometheus/data grafana/datacopy nginx.conf
sh
docker run --rm registry.cn-chengdu.aliyuncs.com/qins-img/openresty:1.27.1.2-jwt cat /usr/local/openresty/nginx/conf/nginx.conf > ./conf/nginx.conf
# 或
# 1. 启动临时容器
docker run --name openresty-temp registry.cn-chengdu.aliyuncs.com/qins-img/openresty:1.27.1.2-jwt
# 2. 拷贝整个 conf 目录到宿主机
docker cp openresty-temp:/usr/local/openresty/nginx/conf ./conf
# 3. 删除临时容器
docker rm -f openresty-tempcopy prometheus 配置
sh
docker run --rm --entrypoint cat prom/prometheus:v2.54.1 /etc/prometheus/prometheus.yml > ./prometheus/prometheus.yml修改 配置,添加 nginx 相关 vim prometheus/prometheus.yml
yml
- job_name: "nginx"
static_configs:
- targets: ["nginx-exporter:9113"]sh
vim docker-compose.ymlyml
networks:
nginx-proxy-net:
external: true
services:
openresty:
image: registry.cn-chengdu.aliyuncs.com/qins-img/openresty:1.27.1.2-jwt
container_name: my-waf-resty
ports:
- "80:80"
- "443:443"
volumes:
- ./conf:/usr/local/openresty/nginx/conf
- ./lua:/usr/local/openresty/lualib/custom
- ./logs:/usr/local/openresty/nginx/logs
- ./conf.d:/etc/nginx/conf.d
- ./ssl:/etc/nginx/ssl
- /mydata/web-static:/mydata/web-static
- ./www:/data/www
- ./www-goaccess:/data/www-goaccess
environment:
- TZ=Asia/Shanghai
restart: unless-stopped
networks:
- nginx-proxy-net
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "5"
nginx-exporter:
image: nginx/nginx-prometheus-exporter:1.1.0
container_name: nginx-exporter
command: ["--nginx.scrape-uri=http://openresty:4102/nginx_status"]
depends_on:
- openresty
networks:
- nginx-proxy-net
prometheus:
image: prom/prometheus:v2.54.1
container_name: prometheus
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus/data:/prometheus
ports:
- "4101:9090"
networks:
- nginx-proxy-net
grafana:
image: grafana/grafana:11.0.0
container_name: grafana
ports:
- "4100:3000"
environment:
- GF_SECURITY_ADMIN_USER=qin
- GF_SECURITY_ADMIN_PASSWORD=你的密码
networks:
- nginx-proxy-net
volumes:
- ./grafana/data:/var/lib/grafana
# - ./grafana/conf:/etc/grafana日志
nginx
http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
log_format nginxlog_json escape=json '{ "timestamp": "$time_iso8601", '
'"remote_addr": "$remote_addr", "body_bytes_sent": $body_bytes_sent, '
'"request_time": $request_time, "response_status": $status, '
'"request": "$request", "request_method": "$request_method", '
'"host": "$host", "upstream_addr": "$upstream_addr", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"http_referrer": "$http_referer", '
'"http_user_agent": "$http_user_agent", '
'"http_version": "$server_protocol", '
'"nginx_access": true }';
access_log logs/access.log main;
access_log /dev/stdout nginxlog_json;
}sudo vim /etc/logrotate.d/my-waf-resty/mydata/my-waf-resty/logs/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
su root root
}sh
# 检查
sudo logrotate -f /etc/logrotate.d/my-waf-resty- daily:每天轮转
- rotate 7:保留最近 7 个文件
- compress:压缩历史日志
- copytruncate:保持 nginx 继续写同一文件
Prometheus + Grafana
admin/gr
goaccess
放弃
goaccess:
image: allinurl/goaccess:latest
container_name: goaccess
depends_on:
- openresty
volumes:
- ./logs:/var/log/nginx:ro
- ./www-goaccess:/var/www/html
ports:
- "7890:7890"
networks:
- nginx-proxy-net
command: >
/var/log/nginx/access.log
--log-format=COMBINED
--real-time-html
-o /var/www/html/report.html
--ws-url=118.25.219.177111
第一步:
完善 OpenResty + 限流 + 黑名单
第二步:
开启基础监控(连接数 + 5xx)
第三步:
再接 Prometheus流量管理( 限流/黑白名)
攻击防护(SQL注入、XSS、CSRF)
日志与可观测
规则管理
- 访问控制(IP、区域、User-Agent、Referer)
- 速率限制(单 IP 限流、全局 QPS 限制)
- 异常流量识别(高频访问、扫描行为)
合格的网关
- 稳定性(不单点)
- 可观测(能看见问题)
- 可控(能封禁)
- 可恢复(崩了能恢复)
- 可扩展(未来能升级)
限流
Nginx 自带
黑名单持久化
Lua 读取 Redis
自动封禁
Lua + Redis