关键是要建立“可复现—可捕获—可回溯”闭环:先启用core dump(ulimit -c unlimited、配置limits.conf、确认core_pattern),再用最小配置逐个验证第三方模块,最后用匹配版本的nginx二进制文件+gdb bt full定位崩溃模块及代码。

排查模块引起的 Nginx 进程核心转储,关键不是等崩溃后再翻日志,而是建立“可复现—可捕获—可回溯”的闭环。核心转储(core dump)是进程崩溃瞬间内存状态的快照,只有拿到它,并用匹配的 nginx 二进制文件加载分析,才能准确定位到是哪个模块、哪行代码、甚至哪个符号冲突导致了段错误。
确认 core dump 已启用并能生成
Linux 下默认常禁用 core dump,需主动放开限制:
- 运行 ulimit -c 查看当前限制;若输出为 0,说明关闭
- 临时开启:ulimit -c unlimited(在启动 nginx 的同一 shell 中执行)
- 永久生效:在 /etc/security/limits.conf 中添加两行
nginx soft core unlimited
nginx hard core unlimited
(注意将 “nginx” 替换为实际运行 nginx 的用户,如 www-data 或 nobody) - 检查内核路径:cat /proc/sys/kernel/core_pattern
若输出为 |/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h,说明 dump 被 systemd 拦截,文件存于 /var/lib/systemd/coredump/,且多为 .xz 压缩格式
快速锁定是否为第三方模块引发
绕过配置干扰,用最小集验证:
- 注释掉 nginx.conf 中所有 load_module 行
- 保留默认模块,执行 nginx -t && nginx -s reload,确认服务稳定运行
- 逐个恢复第三方模块:每次只启用一个 load_module,执行 nginx -t 并观察 error.log 是否出现 segmentation fault、double free 或 core dumped
- 若 nginx -t 静默失败(无输出也无成功提示),大概率是模块加载阶段已出错,此时 strace 可帮上忙:
strace -e trace=openat,open nginx -t 2>&1 | grep '\.so$',看是否卡在某个模块加载环节
用 gdb 分析 core 文件定位模块问题
拿到 core 文件后,必须使用与之完全匹配的 nginx 可执行文件(版本、编译参数、调试符号缺一不可):
- 确认 nginx 版本和构建信息:nginx -V,记录完整 configure 参数及 built by / built with 行
- 若使用系统包(如 apt/yum 安装),安装带调试符号的包(如 nginx-dbg 或 debuginfo-install nginx)
- 加载分析:
gdb /usr/sbin/nginx core.12345
进入后输入 bt full,查看完整调用栈 - 重点关注栈帧中是否出现第三方模块名(如 ngx_http_lua_module、ngx_http_geoip2_module),或崩溃点是否在 SSL_CTX_new、ngx_http_script_flush_complex_value 等易被模块重定义的函数内
结合日志与依赖交叉验证
error.log 和动态链接信息能补全 gdb 看不到的上下文:
- 检查 error.log 中崩溃前的线索:
搜索 undefined symbol:(符号未定义)、relocation error:(重定位失败)、version mismatch(版本不匹配) - 对可疑模块运行:
ldd module.so —— 看是否混链不同版本的 libssl.so 或 libpcre.so
objdump -T module.so | grep nginx_version —— 提取模块内嵌的 NGINX_VERSION 值,必须与 nginx -V 输出数字完全一致(如 1024000 对应 1.24.0) - 若报错含 SSLv2_client_method version OPENSSL_1_1_0 not defined,说明该模块编译时链接的是 OpenSSL 1.1.x,而当前 nginx 使用 OpenSSL 3.x,必须统一 OpenSSL 版本并重编模块


















