动态模块加载失败需三步排查:一查是否编译进nginx(nginx -v | grep dynamic),二查load_module位置及路径是否相对于prefix且文件存在,三查.so权限、abi兼容性及error.log与journalctl日志。

动态模块路径写错不会直接报“路径不存在”,而是表现为 unknown directive 或启动时静默退出。关键要分三步确认:模块是否真被编译进 Nginx、load_module 指令是否合规、.so 文件是否真实可达。
确认模块是否支持动态加载
静态模块(如 ssl、http_v2)不需要 load_module;只有明确以 --add-dynamic-module= 或 --with-xxx_module=dynamic 方式编译的模块,才能用 .so 加载。运行:
-
nginx -V 2>&1 | grep -E "(add-dynamic-module|with-.*_module=dynamic)",看目标模块是否出现在输出中 - 若完全没出现对应关键词,说明该模块根本未编译——此时无论路径怎么改都无效
检查 load_module 指令位置与路径格式
load_module 必须放在 events 块之前、全局域内,且路径是相对于 prefix 的相对路径(不是绝对路径,也不是相对于配置文件的位置):
- 查 prefix:
nginx -V 2>&1 | grep prefix,例如输出--prefix=/usr/share/nginx - 假设配置写了
load_module modules/ngx_http_geoip2_module.so;,那就去检查/usr/share/nginx/modules/ngx_http_geoip2_module.so是否存在 - 用
ls -l $(nginx -V 2>&1 | grep prefix | awk '{print $2}')/modules/一次性列出所有模块文件
验证 .so 文件可读性与 ABI 兼容性
即使文件存在,权限或兼容性问题也会导致加载失败:
- 执行
ls -l /path/to/module.so,确保权限至少为-r-xr-xr-x(Nginx 主进程需有读+执行权) - 运行
nginx -c /etc/nginx/nginx.conf -e stderr,观察终端输出,典型错误包括:
dlopen() "/path/to/module.so" failed: undefined symbol: ngx_http_lua_ffi_req_get_uri(ABI 不匹配,比如 Lua 模块和 LuaJIT 版本不一致)
open() "/path/to/module.so" failed (2: No such file or directory)(路径拼错、软链接断裂、或 prefix 理解错误)
结合 error.log 和 systemd 日志交叉印证
模块加载失败不一定写入默认 error.log,尤其当日志模块自身依赖动态模块时:
- 先确认主配置里
error_log指令指向哪,再查该路径是否有 emerg/error 级报错 - 若日志为空或无相关记录,立即执行:
journalctl -u nginx --no-pager -n 30,过滤关键词:module、dlopen、failed to load - 避免用
systemctl restart nginx直接重试——它会掩盖 stderr 输出;应先用命令行方式手动启动定位











