
最近,我们为Nginx构建了一个动态模块,当一切准备就绪时,事实证明我们的模块与服务器上已安装的Nginx不兼容。 我们找不到解决该问题的现成解决方案,因此我们开始自己进行斗争。 我们花了很多时间,但是有了新的经验,最重要的是,找到了可行的解决方案。 我想分享。
让我们使用示例https://github.com/vozlt/nginx-module-vts来描述动态模块组装过程。 然后,我们将显示发生什么错误以及如何处理。
输入数据:
Debian 9作业系统
来自标准Debian存储库的Nginx v1.10.3。 nginx -V
输出:
nginx version: nginx/1.10.3 built with OpenSSL 1.1.0k 28 May 2019 (running with OpenSSL 1.1.1c 28 May 2019) TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/ nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path =/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module - -with-http_stub_status_module --with-http_realip_mod ule --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module= dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-auth-pam --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-dav-ext-module --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-echo --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-upstream-fair --add-dynamic-module=/build/nginx-DhOtPd/nginx -1.10.3/debian/modules/ngx_http_substitutions_filter_module
此命令的输出包含组装动态模块所需的信息,即在configure arguments:
之后和first- --add-dynamic-module
之前编写的所有内容,即:
--with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/ nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path =/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_mod ule --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module= dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module
因此,我们开始组装模块:
- 对于组装,使用docker容器很方便,以免使主系统混乱,以debian:9映像为基础,为了方便从容器中复制完成的模块,可以指定体积。 在这种情况下,启动容器的命令将如下所示:
docker run --rm -it -v /tmp/nginx_module:/nginx_module debian:9 bash
- 启动容器后,安装必要的软件包。 请注意,这些软件包是根据nginx -V命令的输出选择的,因此您可能不需要某些库。 无论如何,configure脚本都会警告您缺少依赖项:
apt update apt install git make gcc autoconf wget libpcre3-dev libpcre++-dev zlib1g-dev libxml2-dev libxslt-dev libgd-dev libgeoip-dev
该列表中缺少libssl-dev软件包,因为服务器上安装的nginx是使用OpenSSL 1.1.0k版本构建的,在撰写本文时,从存储库安装libssl-dev软件包时,其中的OpenSSL版本已经是1.1.0l。 因此,必须单独下载正确版本的OpenSSL源代码。
cd /usr/local/src/ wget http://nginx.org/download/nginx-1.10.3.tar.gz wget https://www.openssl.org/source/old/1.1.0/openssl-1.1.0k.tar.gz git clone git://github.com/vozlt/nginx-module-vts.git tar xvfz nginx-1.10.3.tar.gz tar xzvf openssl-1.1.0k.tar.gz cd nginx-1.10.3
- 现在您可以运行配置脚本了。 作为脚本参数,我们指出了nginx -V命令输出中的所有参数,这是我在本文开头所写的。 我们还添加了--add-dynamic-module参数来构建nginx-module-vts模块,并通过--with-openssl参数指定带有OpenSSL源文件的目录路径。 最终命令将如下所示:
./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --with-openssl=../openssl-1.1.0k/ --add-dynamic-module=../nginx-module-vts/
configure
脚本完成工作后,我们开始组装模块;我们不需要收集所有的nginx
:
make modules
请注意,此命令仅在nginx
1.9.13版中可用。
- 组装过程完成后,将生成的so文件复制到
volume
,该容器在容器启动时安装:
cp objs/ngx_http_vhost_traffic_status_module.so /nginx_module/
- 接下来,我们将文件放置在目标服务器上,在这种情况下,包含模块的目录位于路径
/usr/share/nginx/modules
。 为了在nginx
启用该模块,我们创建文件/etc/nginx/modules-enabled/mod-http-vhost-traffic-status.conf
,其内容如下:
load_module modules/ngx_http_vhost_traffic_status_module.so;
并在/etc/nginx/modules-enabled
目录中创建指向此文件的符号链接。
完成工作后,我们调用nginx -t
命令,并得到错误:
nginx: [emerg] module "/usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so" is not binary compatible in /etc/nginx/modules-enabled/50-mod-http-vhost-traffic-status.conf:1
而且这里通常会引起一些混乱,因为服务器上安装的源版本和nginx
版本相同,OpenSSL版本也相同,因此configure
脚本的参数也被完整复制。 那怎么办?
要了解此问题,我必须了解nginx如何检查动态模块是否适合它。 src/core/ngx_module.h
( https://github.com/nginx/nginx/blob/master/src/core/ngx_module.h )中位于nginx
源代码中的代码负责此检查。 该文件有很多检查,在这种情况下为34,在此期间nginx为NGX_MODULE_SIGNATURE_0
格式的NGX_MODULE_SIGNATURE_0
(1、2、3等)设置。
值1或0。下一个是变量NGX_MODULE_SIGNATURE
它将所有检查的结果汇总在一行中。 因此,问题在于新模块的签名字符串与现有nginx的签名字符串不匹配。 以下命令可用于检查签名字符串的值:
strings /usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so| fgrep '8,4,8' 8,4,8,000011111101011111111111110110111
strings /usr/sbin/nginx| fgrep '8,4,8' 8,4,8,000011111101011111111111110111111
用肉眼比较这些行时,很明显,在模块签名行中,从末尾开始的第四个变量原来是0,而nginx
有1。要了解模块中到底缺少什么,您需要引用src/core/ngx_module.h
并从末尾找到第四个变量,它看起来像这样:
#if (NGX_HTTP_REALIP) #define NGX_MODULE_SIGNATURE_29 "1" #else #define NGX_MODULE_SIGNATURE_29 "0" #endif #if (NGX_HTTP_HEADERS) #define NGX_MODULE_SIGNATURE_30 "1" #else #define NGX_MODULE_SIGNATURE_30 "0" #endif #if (NGX_HTTP_DAV) #define NGX_MODULE_SIGNATURE_31 "1" #else #define NGX_MODULE_SIGNATURE_31 "0" #endif #if (NGX_HTTP_CACHE) #define NGX_MODULE_SIGNATURE_32 "1" #else #define NGX_MODULE_SIGNATURE_32 "0" #endif #if (NGX_HTTP_UPSTREAM_ZONE) #define NGX_MODULE_SIGNATURE_33 "1" #else #define NGX_MODULE_SIGNATURE_33 "0" #endif #define NGX_MODULE_SIGNATURE
我们对变量NGX_HTTP_HEADERS
感兴趣,在构建nginx
时为1,在构建模块0时。为了使模块使用NGX_HTTP_HEADERS
进行NGX_HTTP_HEADERS
您需要通过添加行have=NGX_HTTP_HEADERS . auto/have
来调整模块源代码目录中的配置文件have=NGX_HTTP_HEADERS . auto/have
have=NGX_HTTP_HEADERS . auto/have
在config.
文件的开头config.
以下是进行更改后配置文件的开始:
ngx_addon_name=ngx_http_vhost_traffic_status_module have=NGX_STAT_STUB . auto/have have=NGX_HTTP_HEADERS . auto/have ...
接下来,进行make clean
,然后重新启动configure
and make modules
。 组装模块后,我们检查其签名字符串,然后看它是否与nginx
字符串匹配:
$ strings /usr/sbin/nginx| fgrep '8,4,8' 8,4,8,000011111101011111111111110111111 $ strings /usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so | fgrep '8,4,8' 8,4,8,000011111101011111111111110111111
之后,该模块将毫无问题地连接,您可以使用nginx
收集高级统计信息。
在您的情况下,签名行以及负责此行中每个位置的变量可能看起来会有所不同。 但是,现在您可以了解模块组装到底出了什么问题并解决问题。
我希望本文可以节省一些时间,因为我个人几次都遇到了模块不适合nginx
的问题,因此,通常,我通过将nginx
与正确的模块一起组装来解决此问题。
另请阅读我们博客上的其他文章: