nginx模块加载顺序由objs/ngx_modules.c中ngx_modules[]数组决定,分编译期静态顺序和运行时初始化顺序:内置核心模块最前,事件模块次之,http框架模块随后,第三方模块按--add-module参数从左到右追加,write_filter模块必须最后;动态模块通过load_module按配置书写顺序加载,不参与初始化排序但影响handler/filter链插入点。

Nginx 的模块加载顺序不是“谁先写谁先用”这么简单,它直接决定模块能否正常工作、配置是否生效、甚至服务会不会崩溃。理解这个顺序,关键要分清两个层面:编译期静态顺序和运行时初始化顺序,二者都体现在同一个地方——objs/ngx_modules.c 文件里的 ngx_modules[] 数组。
模块在数组里的位置 = 初始化先后顺序 = 功能是否可靠
这个数组不是人工手写的,而是 ./configure 脚本根据参数自动生成的。它的排列逻辑有明确优先级:
- 内置核心模块(如
&ngx_core_module、&ngx_http_core_module)永远排在最前面 - 事件模块(如
&ngx_events_module、&ngx_epoll_module)紧随其后 - HTTP 框架模块(
&ngx_http_module、&ngx_http_core_module)接着出现,其中ngx_http_core_module的ctx_index固定为 0,是所有 HTTP 模块的起点 - 第三方模块按
--add-module=参数传入的从左到右顺序依次追加到数组末尾 - 所有 filter 模块中,
&ngx_http_write_filter_module必须排在最后,否则响应体可能被截断或乱序
模块之间存在隐式依赖关系,顺序错位就会出问题:
- 上游健康检查模块(如
nginx_upstream_check_module)必须比proxy_module初始化更早,否则check指令形同虚设,节点状态始终显示为 “up” - 两个功能重叠的 rewrite 增强模块如果同时编译,后初始化的会覆盖前者的钩子注册,导致正则匹配失效或变量丢失
- 若某第三方模块依赖另一个模块导出的函数(比如调用
ngx_http_upstream_add()),但后者初始化太晚,启动时就可能段错误
动态模块(.so 文件)走的是另一套路径:
-
load_module指令只在 main 上下文有效,且必须出现在events和http块之前 - 加载顺序由配置文件中
load_module行的书写顺序决定,但多数情况下不强制要求——除非模块间有符号依赖 - 它不改变
ngx_modules[]结构,而是在运行时通过 dlopen 注入,因此不参与初始化次序竞争,但会影响 handler/filter 链的插入点
验证是否按预期加载:
- 查看
objs/ngx_modules.c,确认第三方模块是否处于期望位置 - 启动时加
-t只能校验语法,真正要看效果得观察 error.log 中是否有undefined symbol或module is not binary compatible - 功能测试比日志更直接:比如启用 geoip2 模块后,访问带
$geoip2_city_name的 location,能输出城市名才算真正就位
本质上,Nginx 不是“加载模块”,而是把模块组织成一条精密协作的流水线。顺序不是约定,而是契约。











