1. 项目概述:为什么你需要一个“原生”的Nginx WAF?
如果你正在管理一个对外提供服务的网站或应用,那么“安全”这个词,大概率已经让你头疼过不止一次了。无论是半夜被DDoS攻击打崩服务器,还是发现数据库被SQL注入拖走,又或者后台管理页面被暴力破解,这些场景对于运维和开发者来说,都像是悬在头顶的达摩克利斯之剑。市面上的商业WAF(Web应用防火墙)功能强大,但动辄数万甚至数十万的年费,对于中小型项目或个人开发者来说,是一笔不小的开销。而云厂商提供的WAF服务,虽然按需付费看似灵活,但在流量突增或遭遇复杂攻击时,账单也可能让你措手不及。
正是在这种背景下,VeryNginx进入了我们的视野。它不是一个独立运行的全新软件,而是一个基于OpenResty(本质上是Nginx + LuaJIT)深度开发的、功能强大的Nginx扩展。它的核心价值在于,让你能在自己完全掌控的Nginx服务器上,以极低的成本(几乎是零),部署一套具备商业WAF核心能力的防护体系。你可以把它理解为一个“乐高积木”式的安全模块,直接嵌入到你现有的Nginx架构中,通过灵活的规则匹配(Matcher)和执行动作(Action),实现对HTTP/HTTPS流量的精细化控制和安全防护。
我最初接触VeryNginx,是因为一个电商项目的促销活动。活动开始前,我们预估了流量,也做了基本的限流,但没想到遭遇了混杂着CC攻击和恶意爬虫的复杂流量。云WAF的规则更新有延迟,临时调整成本又高。情急之下,我尝试部署了VeryNginx,在半小时内就配置好了针对异常访问频率和可疑User-Agent的拦截规则,成功扛过了那波攻击,并且后续的运维成本极低。从那以后,VeryNginx就成了我服务器架构中的“标配”组件。
这篇文章,就是把我这些年使用VeryNginx的经验,从快速部署、核心功能解析到高级策略配置,进行一次系统性的梳理。无论你是想为个人博客加一道防线,还是为企业的关键业务提供一个轻量、可控的防护层,这篇指南都能让你在10分钟内上手,并理解其背后的强大能力。
2. 核心架构与工作原理:Matcher与Action的哲学
在深入安装和配置之前,我们必须先理解VeryNginx的设计哲学。很多工具给你一堆预设规则,你只能开关,却不知其所以然,遇到特殊场景就抓瞎。VeryNginx则不同,它把规则制定的权力完全交给了你,其核心是“匹配-执行”模型,具体由两部分构成:Matcher(匹配器)和Action(执行器)。
2.1 Matcher:如何精准地“抓住”你想要的流量
Matcher是规则的“眼睛”和“大脑”,负责定义什么样的请求会被规则命中。VeryNginx的Matcher能力之所以强大,是因为它将Nginx原生变量和Lua的灵活性结合在了一起,支持多种维度的组合匹配。
核心匹配维度包括:
- 请求基础信息:
Host(域名)、Method(请求方法,如GET、POST)、URI(请求路径)。 - 客户端信息:
User-Agent、Referer、Remote Addr(客户端IP)。 - 请求参数:
Query String(GET参数)、Request Body(POST参数)。 - 请求频率与计数:这是实现CC防护的关键。可以基于IP、Session或全局维度,统计单位时间内的请求次数。
- 自定义变量:你可以通过Lua脚本设置自定义变量,实现更复杂的逻辑判断,例如检查某个Cookie值或特定的Header。
一个Matcher可以由多个条件通过“与”(AND)或“或”(OR)的关系组合而成。例如,你可以定义一个Matcher,匹配“请求方法为POST且URI包含/admin/login且在最近10秒内来自同一IP的请求超过5次”的流量。这种组合能力,让你能描绘出非常精确的“攻击者画像”。
实操心得:定义Matcher时,切忌一开始就设置过于宽泛的规则,比如直接拦截所有包含
union select的请求。这很可能误伤正常的搜索或内容查询。我的建议是,先通过VeryNginx的“请求统计”或“过滤器”功能观察一段时间,了解正常流量的模式,再针对性地制定匹配条件,从“记录日志”开始,确认无误后再升级为“拦截”。
2.2 Action:命中规则后,你想“做什么”
Action是规则的“手”,定义了当请求命中Matcher后,VeryNginx应该采取的行动。这是防护动作发生的地方。
常用的Action类型:
- 拦截(Block):直接向客户端返回一个可配置的拒绝页面(如403 Forbidden),请求不会到达后端应用。这是最直接的防御动作。
- 跳转(Redirect):将请求重定向到另一个URL。可以用于将疑似攻击的请求引向一个“蜜罐”页面,或者进行二次验证。
- 响应(Response):直接返回一个自定义的HTTP响应内容和状态码。比如,对于简单的爬虫,可以直接返回一个空的200 OK,节省后端资源。
- 限速(Limit):对匹配的请求进行速率限制,例如“每秒最多处理该IP的10个此类请求”,超过部分延迟处理或拒绝。这是应对CC攻击的核心手段。
- 计数(Count):仅做统计,不采取实际动作。通常用于调试和观察规则是否被正确触发。
- 脚本(Script):执行一段自定义的Lua脚本。这是最高级的Action,可以实现任何你能用Lua写出来的逻辑,比如复杂的验签、动态黑名单等。
Matcher与Action的协作流程可以简化为:一个HTTP请求到达Nginx → 依次经过VeryNginx定义的规则集 → 检查请求是否满足某条规则的Matcher条件 → 如果满足,则执行该规则对应的Action → 根据Action结果(是否终止请求)决定是否继续下一条规则或到达后端应用。
这种设计使得VeryNginx的规则集非常灵活且强大。你可以创建一条规则,先通过“计数”Action观察某个可疑路径的访问频率,确认是攻击后,再将Action修改为“拦截”。整个调整过程在Web控制台点击即可完成,无需重启Nginx服务。
3. 10分钟极速部署与初始化配置
了解了核心思想后,我们进入实战环节。VeryNginx的部署非常简洁,前提是你的Nginx已经支持了必要的模块。
3.1 环境准备与依赖检查
VeryNginx依赖于OpenResty,或者一个编译了lua-nginx-module、http_stub_status_module、http_ssl_module这三个模块的Nginx。对于绝大多数现代Linux发行版,最简单的方式是直接安装OpenResty。
对于CentOS/RHEL/AlmaLinux/Rocky Linux系列:
# 1. 安装EPEL仓库和必要工具 sudo yum install -y epel-release sudo yum install -y git python3 # 2. 安装OpenResty (推荐方式,替代原生Nginx) sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo sudo yum install -y openresty # 3. 启动OpenResty并设置开机自启 sudo systemctl start openresty sudo systemctl enable openresty对于Ubuntu/Debian系列:
# 1. 安装必要工具 sudo apt update sudo apt install -y git python3 # 2. 安装OpenResty sudo apt install -y software-properties-common sudo add-apt-repository -y ppa:openresty/ppa sudo apt update sudo apt install -y openresty # 3. 启动OpenResty sudo systemctl start openresty sudo systemctl enable openresty安装完成后,通过openresty -v或nginx -v(如果链接正确)可以查看版本。OpenResty默认会包含VeryNginx所需的所有模块。
注意事项:如果你坚持使用自己编译的Nginx,必须确保编译时加入了
--with-http_stub_status_module --with-http_ssl_module --add-module=[lua-nginx-module路径]。对于生产环境,我强烈推荐直接使用OpenResty,省心省力,并且能获得LuaJIT的性能优势和丰富的Lua库生态。
3.2 安装与集成VeryNginx
VeryNginx的安装过程是通过一个Python脚本完成的,它会将自身文件复制到系统目录,并引导你修改Nginx配置。
# 1. 克隆VeryNginx仓库 git clone https://github.com/alexazhou/VeryNginx.git cd VeryNginx # 2. 执行安装脚本 sudo python3 install.py install verynginx安装脚本会交互式地询问你几个问题:
- Nginx配置文件路径:脚本通常会自动找到OpenResty的配置文件路径(如
/usr/local/openresty/nginx/conf/nginx.conf)。请确认该路径是否正确。 - Nginx二进制文件路径:同样,脚本会尝试自动定位
nginx或openresty可执行文件路径。
如果自动检测失败,你需要手动输入正确的路径。安装成功后,你会看到“Successfully installed VeryNginx!”的提示。
关键的一步:配置集成。安装脚本会自动修改你的Nginx主配置文件(nginx.conf),在http块和server块中添加include指令,将VeryNginx的配置文件引入。这个过程至关重要,它建立了Nginx与VeryNginx的桥梁。
安装完成后,你的nginx.conf的http块内会新增类似下面的两行:
http { ... include /opt/verynginx/verynginx/nginx_conf/in_http_block.conf; ... }而在你的某个server块(通常是默认的或主要的server块)内,会新增一行:
server { ... include /opt/verynginx/verynginx/nginx_conf/in_server_block.conf; ... }in_http_block.conf负责加载VeryNginx的核心模块和全局配置,in_server_block.conf则负责在具体的server上下文中应用VeryNginx的规则逻辑。
3.3 启动验证与首次登录
配置集成后,需要重新加载Nginx配置使其生效:
# 测试配置文件语法是否正确 sudo nginx -t # 或 sudo openresty -t # 重新加载配置 sudo nginx -s reload # 或 sudo systemctl reload openresty如果一切顺利,VeryNginx的管理界面就已经启动了。默认情况下,它监听在Nginx服务器的80端口下的/verynginx/index.html路径。
访问管理界面:在浏览器中打开:http://你的服务器IP地址/verynginx/index.html你会看到一个登录页面。默认的用户名和密码都是verynginx。
首次登录后必做的三件事:
- 立即修改默认密码!在管理界面的“系统配置”或“用户管理”中,找到修改密码的选项。使用默认密码是极其危险的行为。
- 检查状态:进入“仪表盘”或“状态”页面,查看VeryNginx的运行状态、请求统计等信息,确认系统已正常接管流量。
- 熟悉界面:花几分钟浏览一下“过滤器”、“自定义动作”、“全局配置”等主要功能区域,了解配置入口在哪里。
至此,一个具备基础WAF能力的Nginx已经部署完成。接下来,我们将赋予它“灵魂”——配置安全规则。
4. 核心防护策略配置实战
一个空的VeryNginx只是一个架子,真正的威力来自于你根据自身业务定制的规则。下面我们针对几种最常见的攻击场景,来配置实战规则。
4.1 防御CC攻击与恶意刷接口
CC攻击通过模拟大量正常用户请求,耗尽服务器资源。VeryNginx防御CC的核心是“频率限制”功能。
场景:保护网站登录接口/api/login,防止暴力破解。配置步骤:
- 进入VeryNginx管理界面,找到“自定义动作”或“过滤器”模块(不同版本名称略有差异,核心是创建规则的地方)。
- 创建Matcher(匹配器):
- 匹配类型:选择“URI”。
- 操作符:选择“包含”或“等于”。对于登录接口,使用“等于”
/api/login更精确。 - 匹配对象:填写
/api/login。 - (可选)增加第二个条件,匹配“请求方法”为“POST”。
- 创建Action(执行器):
- 动作类型:选择“频率限制”或“访问控制”。
- 限制维度:选择“按IP地址”。这是最常用且有效的维度。
- 时间窗口:设置为
60秒。意思是统计每60秒内的请求数。 - 最大请求数:设置为
10。这意味着同一个IP在60秒内对此接口最多发起10次POST请求。 - 超出限制后的动作:选择“拦截”并返回
403,或者选择“跳转”到一个验证码页面。
- 绑定规则:将上面创建的Matcher和Action关联起来,形成一条完整的规则。为其起一个名字,例如“防护-登录接口CC攻击”。
- 保存并应用:VeryNginx的配置是实时生效的,无需重启Nginx。
进阶技巧:对于更复杂的CC攻击(如使用代理IP池),可以结合“按Session限制”或“按全局计数”来防护。例如,针对某个查询耗时的API,可以设置“全局”在1秒内最多处理100次请求,超过部分直接排队或拒绝,防止数据库被拖垮。
4.2 构建SQL注入与XSS通用防护规则
虽然VeryNginx没有预置庞大的攻击特征库,但我们可以利用其强大的字符串匹配功能,构建基础的注入防护。
原理:拦截请求参数(Query String和Body)中包含常见SQL注入或XSS攻击特征的请求。配置步骤:
- 创建Matcher:
- 选择“请求参数”作为匹配对象。
- 操作符选择“包含(正则表达式)”。
- 在值中填入一个简化的正则表达式。例如,一个基础的SQL注入检测正则可以是:
(union\s+select|sleep\(|benchmark\(|extractvalue|updatexml|exec\s+\(|insert\s+into|drop\s+table) - 注意:这个正则非常基础,仅作示例。过于严格的正则会误杀正常请求(比如一篇讲解SQL的文章)。生产环境建议从记录日志开始观察。
- 创建Action:选择“拦截”,可以自定义返回一个提示页面,告知请求被安全策略阻止。
- 绑定并启用规则。
重要警告:WAF的规则过滤永远是一种“辅助”和“缓解”手段,不能替代安全的编码实践。最根本的解决方案是在应用程序层做好参数化查询(防SQL注入)、输出编码(防XSS)。VeryNginx的这类规则,更适合作为一道额外的安全网,拦截那些自动化工具发起的、特征明显的攻击扫描。
4.3 IP黑白名单与地理封锁
对于明确的恶意IP或希望限制访问的地区,可以使用IP黑白名单功能。
配置静态IP黑名单:
- 在管理界面找到“IP黑白名单”或类似功能。
- 选择“黑名单”,添加需要封锁的IP地址或CIDR网段(如
192.168.1.100或203.0.113.0/24)。 - 设置生效时间(永久或指定时间段)。
- 保存后,来自这些IP的请求将被直接拒绝。
基于地理位置的访问控制(需要GeoIP数据库):VeryNginx可以通过集成MaxMind的GeoIP数据库,实现按国家/地区封锁。这需要额外步骤:
- 下载GeoIP数据库文件(如
GeoLite2-Country.mmdb)。 - 在VeryNginx的全局配置中,指定数据库文件路径。
- 创建Matcher,匹配条件为“客户端IP所属国家”,操作符选择“在列表中”,然后勾选你希望屏蔽的国家/地区编码(如
CN,RU)。 - 创建Action为“拦截”或“跳转”。
这个功能对于限制业务只对特定国家开放,或者屏蔽某些攻击高发地区的流量非常有效。
4.4 恶意爬虫与扫描器识别
防御爬虫和扫描器,主要依靠对User-Agent和异常访问行为的识别。
屏蔽特定User-Agent:
- 创建Matcher,匹配类型为“请求头”,头名称为
User-Agent。 - 操作符选择“包含(正则表达式)”。
- 值可以填写一个匹配常见恶意扫描器或垃圾爬虫的正则,例如:
(sqlmap|nmap|nessus|acunetix|dirbuster|w3af|nikto|metasploit) - 创建Action为“拦截”或返回一个假数据。
防御目录遍历与敏感文件扫描:扫描器常会访问诸如/admin/,/phpmyadmin/,/wp-login.php,/etc/passwd等路径。
- 创建Matcher,匹配类型为“URI”,操作符“包含(正则表达式)”。
- 值可以写为:
(\.\./|/\.|/admin|/phpmyadmin|/wp-login|/console|/\.git|/\.env) - 创建Action为“拦截”。
频率限制结合URI模式:对于大量访问不存在的页面(404)的行为,可以定义一个规则:如果同一个IP在1分钟内触发超过50次404错误,则将该IP加入临时黑名单10分钟。这能有效应对探测性扫描。
5. 高级功能与性能调优
当基础防护部署妥当后,我们可以探索VeryNginx更高级的用法,并对其进行调优,以适应生产环境的高负载。
5.1 利用自定义Lua脚本实现复杂逻辑
这是VeryNginx的“王牌”功能。当内置的Matcher和Action无法满足需求时,你可以编写Lua脚本。
场景示例:实现一个简单的动态令牌验证,要求特定API的请求必须携带一个由时间戳和密钥生成的签名。
- 在VeryNginx的“自定义脚本”区域,编写Lua函数。这个函数可以读取请求参数,进行HMAC-SHA256计算,并与客户端传来的签名比对。
- 创建一个Matcher,匹配到需要验证的API路径。
- 创建一个Action,类型选择“脚本”,并调用你刚才编写的Lua函数。
- 在Lua函数中,如果验证失败,直接返回
ngx.exit(ngx.HTTP_FORBIDDEN)来拒绝请求;验证成功则return,让请求继续向下流转。
另一个实用场景:实现一个简单的缓存穿透防护。对于查询不存在的商品ID的请求,在Lua脚本中将其记录到共享内存字典中。当同一ID在短时间内被多次请求时,直接返回空结果,而不去查询后端数据库。
实操心得:Lua脚本非常强大,但也会影响性能。务必确保脚本逻辑简洁高效,避免进行耗时的IO操作(如频繁读写文件、发起网络请求)。复杂的业务逻辑还是应该放在后端应用中处理。VeryNginx的Lua脚本最适合做轻量级、高并发的请求预处理和过滤。
5.2 性能监控与日志分析
VeryNginx自带了基础的请求统计仪表盘,可以查看总请求数、被拦截请求数、IP排名等信息。这对于监控防护效果和发现异常流量非常有用。
增强监控的建议:
- 对接外部监控:VeryNginx的日志格式可以自定义。你可以修改其日志格式,将关键信息(如规则命中情况、客户端IP、URI、处理动作)以JSON格式输出。然后使用Filebeat或Fluentd等工具收集日志,发送到Elasticsearch + Kibana(ELK)或Grafana Loki中,构建更强大的实时监控和告警面板。
- 关注关键指标:
- 拦截率:被VeryNginx拦截的请求占总请求的比例。突然飙升可能意味着正在遭受攻击。
- TOP攻击IP:管理界面会列出触发拦截规则的IP排名,这是你进行IP封禁的重要依据。
- 规则命中Top:查看哪条安全规则被触发得最频繁,有助于你优化规则或确认攻击类型。
5.3 性能调优与注意事项
在流量巨大的场景下,不当的配置可能成为性能瓶颈。
- 规则顺序优化:VeryNginx按规则列表的顺序依次匹配。应将匹配最精确、命中后动作最重(如拦截)的规则放在前面。例如,IP黑名单规则应该放在所有规则的最顶端,因为匹配计算成本极低且能立刻阻断恶意流量。将一些宽泛的、用于统计的规则放在后面。
- 慎用复杂正则:在Matcher中,尤其是对
Request Body进行正则匹配,是非常消耗CPU的操作。对于大型POST请求,可能会显著影响性能。尽量使用字符串匹配(contains)代替正则匹配(regex),或者将规则限定在特定的、关键的URI上。 - 限制频率检查的存储后端:VeryNginx默认使用共享内存来存储频率计数。确保
lua_shared_dict指令配置的内存大小足够。如果规则非常多且时间窗口长,可能需要增加此值。配置位置通常在in_http_block.conf中。 - 连接数限制:VeryNginx运行在Nginx内部,因此Nginx本身的性能调优同样重要。确保
worker_processes、worker_connections、keepalive_timeout等参数根据服务器硬件和业务特点进行了优化。 - 定期审计与更新规则:安全是一个持续的过程。定期查看拦截日志,分析误报和漏报。根据业务变化和新的威胁情报,调整和更新你的Matcher规则。可以将一些成熟的规则(如恶意IP列表)通过脚本定期更新到VeryNginx的配置中。
6. 常见问题排查与运维技巧
即使部署顺利,在实际运行中也可能遇到各种问题。这里记录了一些我踩过的坑和解决方案。
6.1 安装与集成故障
问题1:执行python install.py时提示找不到Nginx配置文件或二进制文件。
- 原因:自动探测失败,或者你使用的是非标准路径安装的OpenResty/Nginx。
- 解决:手动指定路径。可以先通过
which nginx或which openresty找到二进制路径,通过nginx -t输出的信息找到配置文件路径。然后在安装脚本提示时输入正确路径。
问题2:修改配置后,Nginx重启或重载失败。
- 原因:VeryNginx自动添加的
include指令位置可能不正确,或者与现有配置冲突。 - 解决:
- 运行
sudo nginx -t查看具体的错误信息。错误通常会精确到某一行。 - 检查
nginx.conf,确保include /opt/verynginx/.../in_http_block.conf;在http块内,且不在其他块(如server或location)中。 - 检查
include /opt/verynginx/.../in_server_block.conf;是否在你希望生效的server块内。如果你有多个server块(虚拟主机),可能需要为每个需要防护的站点单独添加这行。
- 运行
问题3:管理界面无法访问(404错误)。
- 原因:
in_server_block.conf没有被正确包含到处理请求的server块中;或者该server块监听的端口不对。 - 解决:确认你访问的域名和端口,对应的
server块配置里包含了那句include指令。你也可以暂时在默认的server块里添加,先确保能访问管理界面。
6.2 规则不生效或误拦截
问题1:配置的拦截规则没有效果,攻击请求依然通过了。
- 排查步骤:
- 确认配置已保存并应用:在VeryNginx管理界面修改规则后,务必点击“保存”按钮。有些版本需要点击“应用配置”或“重载Nginx”。
- 检查规则顺序:是否前面有某个规则匹配并执行了
allow动作,导致后面的拦截规则被跳过? - 检查Matcher逻辑:你的Matcher条件是否过于严格?比如大小写敏感、路径末尾的斜杠等细节是否匹配?可以先用“计数”Action测试,看规则是否被触发。
- 查看Nginx错误日志:
/usr/local/openresty/nginx/logs/error.log中可能有Lua脚本执行错误的信息。
问题2:正常用户被误拦截。
- 排查步骤:
- 分析拦截日志:VeryNginx会记录被拦截的请求详情。查看是哪个规则拦截了该请求,以及匹配到的具体参数是什么。
- 审查Matcher:是否是正则表达式过于宽泛?例如,拦截包含
select的请求,可能会误伤一篇关于SQL编程的技术文章。考虑优化正则,或者将规则限制在特定的API路径(如/api/*)下。 - 调整频率限制阈值:对于CC防护,如果正常用户因短时间内多次操作(如快速点击提交按钮)被误伤,可以适当调大“时间窗口”和“最大请求数”,或者引入更复杂的维度(如“IP+User-Agent”组合)。
- 使用“白名单”功能:对于内部IP、合作伙伴IP或已知的合法爬虫(如搜索引擎蜘蛛),将其添加到IP白名单中,使其绕过所有或部分安全规则。
6.3 性能与稳定性问题
问题:启用VeryNginx后,服务器负载明显升高,响应变慢。
- 排查与优化:
- 检查规则复杂度:使用
top或htop命令观察Nginx worker进程的CPU占用。如果很高,很可能是某个包含复杂正则匹配(特别是对$request_body)的规则导致的。尝试禁用部分规则进行排查。 - 限制检查范围:避免对所有请求的所有参数都进行正则匹配。通过Matcher将规则限定在特定的、高风险的URI上(如
/admin/*,/api/*)。 - 调整Nginx/OpenResty参数:增加
worker_processes数量以充分利用多核CPU;优化lua_shared_dict的大小。 - 硬件升级:如果流量确实巨大,WAF的计算本身就会消耗资源。考虑升级CPU,或使用商业WAF/CDN服务作为第一层防护,将VeryNginx作为更内层的、精细化的防护手段。
- 检查规则复杂度:使用
长期运维建议:
- 备份配置:定期备份VeryNginx的配置文件目录(默认在
/opt/verynginx/verynginx/config)。在升级或迁移服务器时至关重要。 - 版本更新:关注VeryNginx的GitHub仓库,及时更新以获得新功能和安全修复。更新前务必在测试环境验证。
- 分层防御:记住,VeryNginx是应用层防护。它应该与网络层的防火墙(如iptables/firewalld)、操作系统安全加固、应用程序自身的安全编码共同构成纵深防御体系,而不是唯一的安全依赖。