Nginx自带的索引功能过于羸弱。好在江湖上还有FancyIndex来替代,这个模块已经获得了官方的认可,可以放心使用。
下面演示在Debian Buster上如何安装FancyIndex。
对于RPM系Linux,模块作者已经提供了打包好的RPM包,可以直接通过yum安装。
通过apt-get获取nginx源码。
目前的FancyIndex支持编译成动态模块,也就意味着,我们可以直接使用apt安装的nginx,只需要将编译出FancyIndex动态模块载入即可。为了保证编译时使用的源码版本和deb包的nginx版本一致,我们通过apt-get获取源码,也可以自行查看版本,去nginx官方下载对应版本。
apt source nginx
下载的源码保存在/usr/local/src目录下,并且为我们自动解压了。我们进入到对应目录下,下载FancyIndex的源码。
cd /usr/local/src
wget https://github.com/aperezdc/ngx-fancyindex/archive/refs/tags/v0.5.2.tar.gz
tar xzvf v0.5.2.tar.gz
Nginx为了保证模块的兼容性,所以会对模块和Nginx的签名进行检查,这个签名取决于编译时的参数,启用了哪些Nginx的功能。
最简单的办法是使用和原本的Nginx完全一样的编译参数进行编译。可以通过nginx -V
查看编译参数。
root@xui:~# nginx -V
nginx version: nginx/1.14.2
built with OpenSSL 1.1.1n 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-FlcIR2/nginx-1.14.2=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --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-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-stream_ssl_preread_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-FlcIR2/nginx-1.14.2/debian/modules/http-auth-pam --add-dynamic-module=/build/nginx-FlcIR2/nginx-1.14.2/debian/modules/http-dav-ext --add-dynamic-module=/build/nginx-FlcIR2/nginx-1.14.2/debian/modules/http-echo --add-dynamic-module=/build/nginx-FlcIR2/nginx-1.14.2/debian/modules/http-upstream-fair --add-dynamic-module=/build/nginx-FlcIR2/nginx-1.14.2/debian/modules/http-subs-filter
可以用完全一样的,但是这样的话,需要很多的依赖,实际上可以适当进行精简。签名的作用是保证Nginx主程序包含动态模块所需要的功能,并且我们只需要最终的模块,既然如此,那么编译参数中的和nginx有关的配置,比如路径,以及其他的动态模块实际上就不是必要的了。
最终我精简得到的结果是下面这样的。注意,不同系统以及版本可能有所不同,可以先尝试一下。关于签名在最后解释是如何进行验证的。
./configure \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-threads \
--add-dynamic-module=../ngx-fancyindex-0.5.2
configure可能会报一些依赖错误,这里我把需要的依赖全部都找出来了。
apt install libssl-dev libpcre++-dev zlib1g-dev
万事俱备,进行编译。
make modules
安装模块,修改Nginx配置文件,载入模块。
install -D objs/ngx_http_fancyindex_module.so /usr/share/nginx/modules
echo "load_module modules/ngx_http_fancyindex_module.so;" > /usr/share/nginx/modules-available/mod_fancyindex.conf
ln -s /usr/share/nginx/modules-available/mod_fancyindex.conf /etc/nginx/modules-enabled/50-mod_fancyindex.conf
nginx -t
nginx -s reload
最后在需要使用文件索引的地方,将原本的autoindex改成fancyindex即可。
location / {
fancyindex on;
fancyindex_exact_size off;
}
更多的使用方法,查看源码说明:https://github.com/aperezdc/ngx-fancyindex
补充:Nginx模块兼容性的问题
如果在编译模块的时候,没有带上特定的功能,那么你在载入模块的时候吧,会遇到二进制不兼容的错误。此报错源于源码src/core/ngx_module.c
中,相关片段如下:
if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"module \"%V\" is not binary compatible",
file);
return NGX_ERROR;
}
这里的NGX_MODULE_SIGNATURE宏定义在src/core/ngx_module.h
中,我们可以看到相关的定义。
#define NGX_MODULE_SIGNATURE_0 \
ngx_value(NGX_PTR_SIZE) "," \
ngx_value(NGX_SIG_ATOMIC_T_SIZE) "," \
ngx_value(NGX_TIME_T_SIZE) ","
#if (NGX_HAVE_KQUEUE)
#define NGX_MODULE_SIGNATURE_1 "1"
#else
#define NGX_MODULE_SIGNATURE_1 "0"
#endif
#if (NGX_HAVE_IOCP)
#define NGX_MODULE_SIGNATURE_2 "1"
#else
#define NGX_MODULE_SIGNATURE_2 "0"
#endif
#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
#define NGX_MODULE_SIGNATURE_3 "1"
#else
#define NGX_MODULE_SIGNATURE_3 "0"
#endif
#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
#define NGX_MODULE_SIGNATURE_4 "1"
#else
#define NGX_MODULE_SIGNATURE_4 "0"
#endif
#if (NGX_HAVE_EVENTFD)
#define NGX_MODULE_SIGNATURE_5 "1"
#else
#define NGX_MODULE_SIGNATURE_5 "0"
#endif
#if (NGX_HAVE_EPOLL)
#define NGX_MODULE_SIGNATURE_6 "1"
#else
#define NGX_MODULE_SIGNATURE_6 "0"
#endif
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
#define NGX_MODULE_SIGNATURE_7 "1"
#else
#define NGX_MODULE_SIGNATURE_7 "0"
#endif
#if (NGX_HAVE_INET6)
#define NGX_MODULE_SIGNATURE_8 "1"
#else
#define NGX_MODULE_SIGNATURE_8 "0"
#endif
#define NGX_MODULE_SIGNATURE_9 "1"
#define NGX_MODULE_SIGNATURE_10 "1"
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
#define NGX_MODULE_SIGNATURE_11 "1"
#else
#define NGX_MODULE_SIGNATURE_11 "0"
#endif
#define NGX_MODULE_SIGNATURE_12 "1"
#if (NGX_HAVE_SETFIB)
#define NGX_MODULE_SIGNATURE_13 "1"
#else
#define NGX_MODULE_SIGNATURE_13 "0"
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
#define NGX_MODULE_SIGNATURE_14 "1"
#else
#define NGX_MODULE_SIGNATURE_14 "0"
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
#define NGX_MODULE_SIGNATURE_15 "1"
#else
#define NGX_MODULE_SIGNATURE_15 "0"
#endif
#if (NGX_HAVE_VARIADIC_MACROS)
#define NGX_MODULE_SIGNATURE_16 "1"
#else
#define NGX_MODULE_SIGNATURE_16 "0"
#endif
#define NGX_MODULE_SIGNATURE_17 "0"
#define NGX_MODULE_SIGNATURE_18 "0"
#if (NGX_HAVE_OPENAT)
#define NGX_MODULE_SIGNATURE_19 "1"
#else
#define NGX_MODULE_SIGNATURE_19 "0"
#endif
#if (NGX_HAVE_ATOMIC_OPS)
#define NGX_MODULE_SIGNATURE_20 "1"
#else
#define NGX_MODULE_SIGNATURE_20 "0"
#endif
#if (NGX_HAVE_POSIX_SEM)
#define NGX_MODULE_SIGNATURE_21 "1"
#else
#define NGX_MODULE_SIGNATURE_21 "0"
#endif
#if (NGX_THREADS || NGX_COMPAT)
#define NGX_MODULE_SIGNATURE_22 "1"
#else
#define NGX_MODULE_SIGNATURE_22 "0"
#endif
#if (NGX_PCRE)
#define NGX_MODULE_SIGNATURE_23 "1"
#else
#define NGX_MODULE_SIGNATURE_23 "0"
#endif
#if (NGX_HTTP_SSL || NGX_COMPAT)
#define NGX_MODULE_SIGNATURE_24 "1"
#else
#define NGX_MODULE_SIGNATURE_24 "0"
#endif
#define NGX_MODULE_SIGNATURE_25 "1"
#if (NGX_HTTP_GZIP)
#define NGX_MODULE_SIGNATURE_26 "1"
#else
#define NGX_MODULE_SIGNATURE_26 "0"
#endif
#define NGX_MODULE_SIGNATURE_27 "1"
#if (NGX_HTTP_X_FORWARDED_FOR)
#define NGX_MODULE_SIGNATURE_28 "1"
#else
#define NGX_MODULE_SIGNATURE_28 "0"
#endif
#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
#if (NGX_COMPAT)
#define NGX_MODULE_SIGNATURE_34 "1"
#else
#define NGX_MODULE_SIGNATURE_34 "0"
#endif
#define NGX_MODULE_SIGNATURE \
NGX_MODULE_SIGNATURE_0 NGX_MODULE_SIGNATURE_1 NGX_MODULE_SIGNATURE_2 \
NGX_MODULE_SIGNATURE_3 NGX_MODULE_SIGNATURE_4 NGX_MODULE_SIGNATURE_5 \
NGX_MODULE_SIGNATURE_6 NGX_MODULE_SIGNATURE_7 NGX_MODULE_SIGNATURE_8 \
NGX_MODULE_SIGNATURE_9 NGX_MODULE_SIGNATURE_10 NGX_MODULE_SIGNATURE_11 \
NGX_MODULE_SIGNATURE_12 NGX_MODULE_SIGNATURE_13 NGX_MODULE_SIGNATURE_14 \
NGX_MODULE_SIGNATURE_15 NGX_MODULE_SIGNATURE_16 NGX_MODULE_SIGNATURE_17 \
NGX_MODULE_SIGNATURE_18 NGX_MODULE_SIGNATURE_19 NGX_MODULE_SIGNATURE_20 \
NGX_MODULE_SIGNATURE_21 NGX_MODULE_SIGNATURE_22 NGX_MODULE_SIGNATURE_23 \
NGX_MODULE_SIGNATURE_24 NGX_MODULE_SIGNATURE_25 NGX_MODULE_SIGNATURE_26 \
NGX_MODULE_SIGNATURE_27 NGX_MODULE_SIGNATURE_28 NGX_MODULE_SIGNATURE_29 \
NGX_MODULE_SIGNATURE_30 NGX_MODULE_SIGNATURE_31 NGX_MODULE_SIGNATURE_32 \
NGX_MODULE_SIGNATURE_33 NGX_MODULE_SIGNATURE_34
最终生成的签名长这样:8,4,8,0011111111010111001111111111111111。
根据这些定义和签名,我们其实可以判断出需要添加哪些编译参数。所以如何获取到这个签名呢?
我通过objdump这个工具,对nginx进行反编译,得到汇编代码,字符串常量存放于.rodata
片段,通过一些模糊的查找,不难得出完整的签名。
root@xui:~# objdump -j .rodata -s /usr/sbin/nginx |grep -n 8,4,8
300: d0270 382c342c 382c3030 30303131 31313131 8,4,8,0000111111
1696: d59b0 696f6e5f 69645f63 6f6e7465 78742829 ion_id_context()
root@xui:~# objdump -j .rodata -s /usr/sbin/nginx |sed -n "300,+2p"
d0270 382c342c 382c3030 30303131 31313131 8,4,8,0000111111
d0280 30313031 31313030 31313131 31313131 0101110011111111
d0290 31313131 31313130 00000000 7926f5ff 11111110....y&..
参考一些文章:
https://www.cnblogs.com/weifeng1463/p/15536573.html
https://blog.csdn.net/zhangge3663/article/details/108753118
https://developer.aliyun.com/article/780347
写在最后
其实到最后我才发现我做了一个无用功,Github源码中只提及了rpm包,我便以为debian没有提供,回过头来想,debian在国外比redhat系要流行的多,也开放很多,人家的官方仓库已经收录了这个模块,可以直接通过包管理工具进行安装。
apt install nginx-extras
在这个过程中学到了很多,也不算浪费时间。