概述
本章,您将学习到 Nginx 中模块的添加与使用。
Apache httpd 中的模块
先来回顾下 Apache httpd 当作的模块。
Apache httpd 采用的是模块化架构,其核心只包含主要功能,而拓展功能则通过模块实现。所谓模块化,指将各个功能和特性进行分离,这么做的好处有:
- 拓展性强 - 需要什么功能就加载什么模块,不用修改核心代码,通过 LoadModule 指令配置后 reload 即可生效或停用,非常灵活
- 依赖性弱 - 各个模块功能独立、接口清晰,一个模块的改动不会影响其他模块,模块之间通过标准化的钩子(hook)机制协作,耦合度很低
- 方便后期维护 - 问题定位更容易,出问题时可以快速排查是哪个模块导致的;升级、修复也只需要替换对应的模块,不需要重新编译整个服务器
提到模块,就不得不提到 DSO(Dynamic Shared Object,动态共享对象)技术,模块的动态加载就是通过 DSO 实现的。所谓「动态加载」,指的是需要新功能时,只需要把功能模块编译出来并通过配置文件加载到 Apache httpd 服务当中,而不需要重新编译整个 Apache httpd。不像有些开源的程序/服务,一旦编译且安装完成后,其功能都是固定的,当需要添加新功能时,必须要重新编译整个程序/服务。
列出所有已经编译进 Apache 内核的静态模块:
Shell > /usr/local/apache2/bin/apachectl -l
Compiled in modules:
core.c
mod_so.c
http_core.c
显示当前 Apache 服务器已加载的所有模块(包括编译进内核的静态模块,也包括通过 LoadModule 指令动态加载的模块):
Shell > /usr/local/apache2/bin/apachectl -M
Loaded Modules:
core_module (static)
so_module (static)
http_module (static)
mpm_event_module (shared)
authn_file_module (shared)
authn_core_module (shared)
authz_host_module (shared)
authz_groupfile_module (shared)
authz_user_module (shared)
authz_core_module (shared)
access_compat_module (shared)
auth_basic_module (shared)
reqtimeout_module (shared)
filter_module (shared)
mime_module (shared)
log_config_module (shared)
env_module (shared)
headers_module (shared)
setenvif_module (shared)
version_module (shared)
unixd_module (shared)
status_module (shared)
autoindex_module (shared)
dir_module (shared)
alias_module (shared)
括号里标注 static,表示该模块已静态编译进 Apache 内核,即所谓的静态编译模块;而标注为 shared,则表示该模块以 DSO 方式动态加载,即所谓的动态加载模块。
在 Apache httpd 中,若缺少了相关功能,可通过 apxs 命令进行操作(该命令用来对模块的源文件进行动态编译,使之成为 DSO 模块)。动态编译成功后,对应模块相关的 .so 文件会添加到 /usr/local/apache2/modules/ 目录中且主配置文件 httpd.conf 中会使用 LoadModule 指令来加载这些 .so 文件。
Apache httpd 中静态模块的不同名称表述:
- 静态编译模块 - 官方名称
- 静态模块 - 属于日常交流的通俗名称,不属于 Apache 官方文档里的标准正式名称
Apache httpd 中动态模块的不同名称表述:
- DSO 模块 - 官方名称
- 动态加载模块 - 对模块加载行为的功能性描述,属于通用技术表述,并非 Apache 官方指定的专属正式名称
- 动态模块 - 相对静态模块的通俗简称,在日常运维交流中常用,不属于 Apache 官方文档里的标准正式名称
Nginx 中的模块
如同 Apache httpd 的模块一样,在 Nginx 中,模块分为两大类:
-
静态模块 - 在源码编译期间,通过编译选项直接编译进 Nginx 的二进制主程序中,编译完成后,可通过
nginx -V查看所有内置的静态模块。静态模块是 Nginx 核心功能的主要载体。查看当前 Nginx 的静态模块(所有以 --with- 开头的选项即代表已静态编译进主程序的模块):
Shell > /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.30.4 built by gcc 8.5.0 20210514 (Red Hat 8.5.0-28) (GCC) built with OpenSSL 1.1.1k FIPS 25 Mar 2021 TLS SNI support enabled configure arguments: --prefix=/usr/local/nginx --sbin-path=/usr/local/nginx/sbin/nginx --modules-path=/usr/local/nginx/modules --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_v3_module --with-http_realip_module --with-http_gzip_static_module --with-http_dav_module --with-stream --with-threads --with-file-aio -
动态模块 - 从 Nginx 1.9.11 版本开始正式引入该特性,类似 Apache httpd 当中的 DSO 模块,Nginx 中的动态模块文件也是以独立的 .so 形式存在。在使用时,您需要在主配置文件 nginx.conf 中使用
load_module指令来加载这些 .so 动态库文件。动态模块的提供方可大致划分为三个方向:- 官方维护的动态模块(NGINX-authored) - acme、geoip、image-filter、njs、otel、perl、xslt
- 官方测试打包的知名第三方动态模块(NGINX-certified community) - brotli、geoip2、headers-more、subs-filter、lua、ndk、set-misc、rtmp、auth-spnego、encrypted-session、fips-check、passenger
- 商业合作伙伴提供的动态模块(NGINX Certified Partner) - 主要服务于 Nginx Plus(Nginx 的商业版本)。社区版本 Nginx 可尝试使用
load_module指令加载但无兼容性保证,在生产环境中不推荐
使用动态模块的前置条件
在社区版 Nginx 当中使用动态模块必须满足这些前置条件:
- Nginx 的版本必须大于等于 1.9.11
nginx -V命令的输出中 必须 包含--with-compat或显示支持 dynamic modules。若输出中缺少这些内容,您必须重新编译安装 Nginx,否则无法使用动态模块。load_module指令必须放在 main 上下文中且必须书写在 events 上下文的前面- Nginx 中动态模块对 ABI(Application Binary Interface,应用二进制接口)的要求极其严格,需要新手注意。您编译动态模块的环境必须与初始编译安装 Nginx 的环境(GCC 版本、PCRE 版本、OpenSSL 版本等)一致,否则后续容易出现 「module "xxx" is not binary compatible」 的错误
动态模块的添加与使用
满足使用动态模块的前置条件
由于我当前的 Nginx 不满足使用动态模块的前置条件,因此必须重新编译安装 Nginx。
在重新编译安装 Nginx 之前,我需要备份相关的文件。
PS > cd E:\
PS > scp -P 22 root@192.168.100.20:/usr/local/nginx/conf/nginx.conf .
PS > scp -P 22 root@192.168.100.20:/html/games/index.html .
重新编译安装 Nginx:
# 删除无法使用动态模块的 Nginx
Shell > rm -rf /usr/local/nginx
Shell > cd /usr/local/src/nginx-1.30.4/
# 等待编译工作的完成
Shell > ./configure \
--prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_v3_module \
--with-http_realip_module \
--with-http_gzip_static_module \
--with-http_dav_module \
--with-stream \
--with-threads \
--with-file-aio \
--with-compat \
&& make && make install
# 输出中包含了 "--with-compat"
Shell > /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.30.4
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-28) (GCC)
built with OpenSSL 1.1.1k FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --sbin-path=/usr/local/nginx/sbin/nginx --modules-path=/usr/local/nginx/modules --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_v3_module --with-http_realip_module --with-http_gzip_static_module --with-http_dav_module --with-stream --with-threads --with-file-aio --with-compat
在 Windows 10/11 上传备份的主配置文件:
PS > cd E:\
PS > scp -P 22 .\nginx.conf root@192.168.100.20:/tmp/
# 利用输出重定向覆盖 nginx.conf 的内容
Shell > cat /tmp/nginx.conf > /usr/local/nginx/conf/nginx.conf
# 测试配置文件
Shell > /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
下面演示了如何在 Nginx 中添加并使用 hello world 动态模块,这是一个极其简单的例子。
添加
# 利用 git 克隆模块的 git 项目地址
Shell > git clone https://github.com/perusio/nginx-hello-world-module.git
# 查看目录中内容
Shell > ls -l /root/nginx-hello-world-module/
total 16
-rw-r--r-- 1 root root 375 Sep 7 17:47 config
-rw-r--r-- 1 root root 5239 Sep 7 17:47 ngx_http_hello_world_module.c
-rw-r--r-- 1 root root 2429 Sep 7 17:47 README.md
# 通过阅读 README.md 文件,使用者需要执行这样的操作
Shell > cd /usr/local/src/nginx-1.30.4/
Shell > ./configure --with-compat --add-dynamic-module=/root/nginx-hello-world-module && make modules
# 编译动态模块成功后对应 .so 文件会存放在 "objs/" 目录中:
Shell > ls -lh /usr/local/src/nginx-1.30.4/objs/ngx_http_hello_world_module.so
-rwxr-xr-x 1 root root 68K Sep 7 17:54 /usr/local/src/nginx-1.30.4/objs/ngx_http_hello_world_module.so
Shell > mkdir /usr/local/nginx/modules
Shell > cp -p /usr/local/src/nginx-1.30.4/objs/ngx_http_hello_world_module.so /usr/local/nginx/modules/
# 变更文件的所有者、所属组以及它们的权限
Shell > chown nginx:nginx /usr/local/nginx/modules/ngx_http_hello_world_module.so && chmod 755 /usr/local/nginx/modules/ngx_http_hello_world_module.so
使用
# 在主配置文件中利用 load_module 指令加载 .so 文件
## 注意!load_module 指令需要书写在 events 上下文的上面
Shell > grep -i load /usr/local/nginx/conf/nginx.conf
load_module modules/ngx_http_hello_world_module.so;
# 测试配置文件的语法
Shell > /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
修改主配置文件:
Shell > vim /usr/local/nginx/conf/nginx.conf
user nginx;
worker_processes 4;
error_log logs/error.log error;
pid logs/nginx.pid;
worker_rlimit_nofile 7400;
load_module modules/ngx_http_hello_world_module.so;
events {
use epoll;
worker_connections 1024;
multi_accept on;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
tcp_nopush on;
keepalive_timeout 30;
server_tokens off;
gzip on;
gzip_vary on;
gzip_buffers 32 4K;
gzip_comp_level 5;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/xhtml+xml image/svg+xml application/x-font-ttf application/x-font-opentype application/vnd.ms-fontobject font/woff;
gzip_min_length 256;
server {
listen 192.168.100.20:80;
server_name www.games.com;
access_log logs/games-access.log main;
charset utf-8;
location / {
root /html/games/;
index index.html index.htm;
location ~* \.(jpg|css|jpeg|xml|js|gif) {
expires 4h;
}
}
location /images/ {
alias /var/www/attachment/;
autoindex on;
autoindex_exact_size off;
autoindex_localtime off;
autoindex_format html;
}
location /test/ {
hello_world;
}
}
}
启动 Nginx 并尝试访问:
Shell > /usr/local/nginx/sbin/nginx -t && /usr/local/nginx/sbin/nginx
# 返回 "hello world" 字符串的响应正文
Shell > curl -i http://192.168.100.20/test/
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 07 Sep 2026 10:16:56 GMT
Content-Type: text/plain
Content-Length: 13
Connection: keep-alive
hello world
对于其他动态模块的使用,需要系统管理员阅读项目的 README.md 文件或查阅官方文档,一般情况下都不会太难。










