nginx模块加载顺序决定初始化时机与执行链位置:静态模块顺序由configure生成的ngx_modules.c数组固定,内置核心模块最前,事件模块次之,http框架模块须在第三方http模块之前,write_filter必须最后;动态模块通过load_module按配置书写顺序注入,依赖模块须先加载,否则报undefined symbol。

Nginx 模块的加载顺序与依赖管理,本质是控制模块在启动时的初始化时机和执行链位置。顺序不对,轻则配置不生效,重则服务启动失败或响应异常。关键不在“怎么写配置”,而在于“什么时候、以什么方式让模块进入系统”。
静态模块:编译期就定死顺序
所有通过 --add-module 编译进二进制的模块,顺序由 configure 脚本生成的 objs/ngx_modules.c 文件决定。这个数组就是最终加载顺序:
- 内置核心模块(如
&ngx_core_module)永远排最前 - 事件模块(如
&ngx_epoll_module)紧随其后 - HTTP 框架模块(
&ngx_http_module和&ngx_http_core_module)必须在第三方 HTTP 模块之前 - 第三方模块按 --add-module=路径 的传入顺序从左到右追加
- filter 类模块中,
&ngx_http_write_filter_module必须排在最后,否则响应体可能被截断 - 上游健康检查模块(如
nginx_upstream_check_module)必须比ngx_http_proxy_module初始化更早,否则 check 指令无效
动态模块:运行时加载,但插入点仍受约束
动态模块(.so 文件)不改变 ngx_modules[] 数组,但通过 load_module 指令在运行时注入。它不参与初始化排序,却直接影响 handler/filter 链的插入位置:
-
load_module只能在 main 上下文使用,且必须出现在events和http块之前 - 加载顺序由配置中
load_module行的书写顺序决定 - 若模块 A 依赖模块 B 导出的函数(比如调用
ngx_http_upstream_add()),B 必须先加载,否则启动时报undefined symbol - 动态模块启用后,其指令(如
brotli on)才能在http或server块中生效
验证与排查:别只信配置语法
nginx -t 只能校验语法,真正要看模块是否按预期加载,得结合三方面:
- 查看
objs/ngx_modules.c,确认第三方模块在数组中的位置是否符合逻辑 - 启动时观察
error.log,留意module is not binary compatible或undefined symbol等错误 - 做功能验证:比如启用
geoip2后,访问含$geoip2_city_name的 location,看变量是否输出;启用健康检查后,手动停掉 upstream 节点,观察状态是否变为down
依赖处理的核心原则
模块间不是松散拼接,而是存在明确的上下文依赖关系:
- HTTP 模块必须等
ngx_http_core_module初始化完成才能注册自己的 handler - rewrite 增强模块如果同时存在两个,后初始化的那个会覆盖前者的钩子,导致正则失效
- 自定义 filter 模块若插在 write_filter 之前,但没正确调用 next filter,响应就会卡住
- 编译时若漏装开发库(如 brotli 库未安装),
make modules会静默跳过该模块,不报错也不生成 .so











