Nginx功能篇08—模块的添加与使用

概述

本章,您将学习到 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 文件或查阅官方文档,一般情况下都不会太难。

Avatar photo

关于 陸風睿

GNU/Linux 从业者、开源爱好者、技术钻研者,撰写文档既是兴趣也是工作内容之一。Q - "281957576";WeChat - "jiulongxiaotianci",Github - https://github.com/jimcat8
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇