Skip to content

Nginx 模块系统

Nginx 采用模块化架构,通过各种模块提供丰富的功能。本章将介绍 Nginx 的模块系统、常用模块和第三方扩展。

🧩 模块架构

模块类型

Nginx 模块分类:
├── 核心模块 (Core Modules)
│   ├── ngx_core_module
│   ├── ngx_errlog_module
│   └── ngx_conf_module
├── 事件模块 (Event Modules)
│   ├── ngx_events_module
│   ├── ngx_epoll_module
│   └── ngx_kqueue_module
├── HTTP 模块 (HTTP Modules)
│   ├── ngx_http_core_module
│   ├── ngx_http_access_module
│   ├── ngx_http_auth_basic_module
│   └── ...
├── 邮件模块 (Mail Modules)
│   ├── ngx_mail_core_module
│   ├── ngx_mail_pop3_module
│   └── ngx_mail_imap_module
└── 流模块 (Stream Modules)
    ├── ngx_stream_core_module
    ├── ngx_stream_proxy_module
    └── ngx_stream_upstream_module

查看已安装模块

bash
# 查看编译时包含的模块
nginx -V

# 查看动态模块
ls /usr/lib/nginx/modules/

# 查看模块配置
nginx -T | grep -E "(load_module|--with-|--add-)"

🔧 核心 HTTP 模块

ngx_http_core_module

nginx
# 核心 HTTP 配置
http {
    # 服务器名称哈希
    server_names_hash_bucket_size 128;
    server_names_hash_max_size 512;
    
    # 变量哈希
    variables_hash_bucket_size 128;
    variables_hash_max_size 512;
    
    # 类型哈希
    types_hash_bucket_size 64;
    types_hash_max_size 1024;
    
    # 连接处理
    keepalive_timeout 65;
    keepalive_requests 100;
    
    # 客户端配置
    client_max_body_size 100m;
    client_body_timeout 60s;
    client_header_timeout 60s;
}

ngx_http_access_module

nginx
server {
    listen 80;
    server_name example.com;
    
    # IP 访问控制
    location /admin/ {
        allow 192.168.1.0/24;
        allow 10.0.0.0/8;
        deny all;
    }
    
    # 特定文件访问控制
    location ~ \.(htaccess|htpasswd|ini|log)$ {
        deny all;
    }
    
    # 组合访问控制
    location /api/ {
        allow 192.168.1.100;
        allow 203.0.113.0/24;
        deny all;
        
        proxy_pass http://backend;
    }
}

ngx_http_auth_basic_module

nginx
server {
    listen 80;
    server_name secure.example.com;
    
    # 全站认证
    auth_basic "Restricted Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
    
    location / {
        root /var/www/secure;
        index index.html;
    }
    
    # 特定目录认证
    location /admin/ {
        auth_basic "Admin Area";
        auth_basic_user_file /etc/nginx/.htpasswd_admin;
        
        root /var/www/admin;
    }
    
    # 禁用认证
    location /public/ {
        auth_basic off;
        root /var/www/public;
    }
}

ngx_http_rewrite_module

nginx
server {
    listen 80;
    server_name example.com;
    
    # 基本重写
    rewrite ^/old-page$ /new-page permanent;
    rewrite ^/blog/(.*)$ /posts/$1 redirect;
    
    # 条件重写
    if ($host ~* "^www\.(.+)$") {
        return 301 https://$1$request_uri;
    }
    
    # 复杂重写规则
    location / {
        # 移除 .html 扩展名
        if ($request_uri ~ ^/(.*)\.html$) {
            return 301 /$1;
        }
        
        # 尝试文件,然后添加 .html
        try_files $uri $uri.html $uri/ =404;
    }
    
    # 使用 map 进行重写
    map $request_uri $new_uri {
        ~^/old/(.*)$ /new/$1;
        ~^/legacy/(.*)$ /modern/$1;
        default "";
    }
    
    if ($new_uri != "") {
        return 301 $new_uri;
    }
}

📊 监控和状态模块

ngx_http_stub_status_module

nginx
server {
    listen 80;
    server_name localhost;
    
    location /nginx_status {
        stub_status on;
        access_log off;
        
        # 访问控制
        allow 127.0.0.1;
        allow 192.168.1.0/24;
        deny all;
    }
}

状态页面输出:

Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106

ngx_http_realip_module

nginx
# 获取真实客户端 IP
server {
    listen 80;
    server_name example.com;
    
    # 设置可信代理
    set_real_ip_from 192.168.1.0/24;
    set_real_ip_from 10.0.0.0/8;
    set_real_ip_from 172.16.0.0/12;
    
    # 从哪个头部获取真实 IP
    real_ip_header X-Forwarded-For;
    # real_ip_header X-Real-IP;
    # real_ip_header proxy_protocol;
    
    # 递归查找
    real_ip_recursive on;
    
    location / {
        # 记录真实 IP
        access_log /var/log/nginx/realip.log;
        proxy_pass http://backend;
    }
}

🗜️ 压缩和缓存模块

ngx_http_gzip_module

nginx
http {
    # 基础压缩配置
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    
    # 压缩类型
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;
    
    # 代理压缩
    gzip_proxied any;
    
    # 禁用压缩的条件
    gzip_disable "msie6";
}

ngx_http_gzip_static_module

nginx
server {
    listen 80;
    server_name example.com;
    
    location ~* \.(css|js)$ {
        # 查找预压缩文件
        gzip_static on;
        
        # 缓存配置
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Vary Accept-Encoding;
    }
}

ngx_http_headers_module

nginx
server {
    listen 80;
    server_name example.com;
    
    # 添加安全头
    add_header X-Frame-Options DENY always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    # 条件添加头
    location ~* \.(css|js|png|jpg|gif)$ {
        add_header Cache-Control "public, max-age=31536000";
        add_header Vary Accept-Encoding;
        expires 1y;
    }
    
    # 移除头部
    location /api/ {
        proxy_pass http://backend;
        proxy_hide_header X-Powered-By;
        proxy_hide_header Server;
    }
}

🔒 安全模块

ngx_http_limit_req_module

nginx
http {
    # 定义限流区域
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $server_name zone=perserver:10m rate=100r/s;
    
    server {
        listen 80;
        server_name example.com;
        
        # 登录接口限流
        location /login {
            limit_req zone=login burst=5 nodelay;
            proxy_pass http://backend;
        }
        
        # API 接口限流
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_req zone=perserver burst=200 nodelay;
            proxy_pass http://backend;
        }
        
        # 自定义错误页面
        error_page 429 /rate_limit.html;
        location = /rate_limit.html {
            root /var/www/error;
            internal;
        }
    }
}

ngx_http_limit_conn_module

nginx
http {
    # 定义连接限制区域
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    limit_conn_zone $server_name zone=perserver:10m;
    
    server {
        listen 80;
        server_name example.com;
        
        # 限制每个 IP 的连接数
        limit_conn addr 10;
        
        # 限制服务器总连接数
        limit_conn perserver 1000;
        
        # 限制连接速度
        location /downloads/ {
            limit_conn addr 1;
            limit_rate 1m;  # 1MB/s
            limit_rate_after 10m;  # 前 10MB 不限速
        }
    }
}

🌐 第三方模块

nginx-module-vts (流量统计)

bash
# 编译安装
./configure --add-module=/path/to/nginx-module-vts
make && make install
nginx
http {
    vhost_traffic_status_zone;
    
    server {
        listen 80;
        server_name example.com;
        
        location /status {
            vhost_traffic_status_display;
            vhost_traffic_status_display_format html;
            access_log off;
        }
    }
}

nginx-upload-module (文件上传)

nginx
server {
    listen 80;
    server_name upload.example.com;
    
    location /upload {
        upload_pass /upload_handler;
        upload_store /tmp/nginx_upload;
        upload_store_access user:rw group:rw all:r;
        
        upload_set_form_field $upload_field_name.name "$upload_file_name";
        upload_set_form_field $upload_field_name.content_type "$upload_content_type";
        upload_set_form_field $upload_field_name.path "$upload_tmp_path";
        
        upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
        upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";
        
        upload_cleanup 400 404 499 500-505;
    }
    
    location /upload_handler {
        proxy_pass http://backend;
    }
}

lua-resty-core (Lua 脚本)

nginx
# 需要 OpenResty 或编译 lua 模块
server {
    listen 80;
    server_name lua.example.com;
    
    location /lua {
        content_by_lua_block {
            ngx.say("Hello from Lua!")
            ngx.say("Request method: ", ngx.var.request_method)
            ngx.say("Request URI: ", ngx.var.request_uri)
        }
    }
    
    location /api/ {
        access_by_lua_block {
            -- 自定义认证逻辑
            local auth_header = ngx.var.http_authorization
            if not auth_header then
                ngx.status = 401
                ngx.say("Unauthorized")
                ngx.exit(401)
            end
        }
        
        proxy_pass http://backend;
    }
}

🔧 动态模块

加载动态模块

nginx
# 在主配置文件顶部加载模块
load_module modules/ngx_http_image_filter_module.so;
load_module modules/ngx_http_geoip_module.so;
load_module modules/ngx_stream_module.so;

http {
    # 使用加载的模块
    server {
        listen 80;
        server_name example.com;
        
        location /resize/ {
            image_filter resize 300 200;
            image_filter_jpeg_quality 95;
        }
    }
}

编译动态模块

bash
# 编译第三方动态模块
./configure --with-compat --add-dynamic-module=/path/to/module
make modules

# 复制模块文件
cp objs/*.so /usr/lib/nginx/modules/

📊 模块开发

简单模块示例

c
// ngx_http_hello_module.c
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

static char *ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r);

static ngx_command_t ngx_http_hello_commands[] = {
    {
        ngx_string("hello"),
        NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
        ngx_http_hello,
        0,
        0,
        NULL
    },
    ngx_null_command
};

static ngx_http_module_t ngx_http_hello_module_ctx = {
    NULL,                          /* preconfiguration */
    NULL,                          /* postconfiguration */
    NULL,                          /* create main configuration */
    NULL,                          /* init main configuration */
    NULL,                          /* create server configuration */
    NULL,                          /* merge server configuration */
    NULL,                          /* create location configuration */
    NULL                           /* merge location configuration */
};

ngx_module_t ngx_http_hello_module = {
    NGX_MODULE_V1,
    &ngx_http_hello_module_ctx,    /* module context */
    ngx_http_hello_commands,       /* module directives */
    NGX_HTTP_MODULE,               /* module type */
    NULL,                          /* init master */
    NULL,                          /* init module */
    NULL,                          /* init process */
    NULL,                          /* init thread */
    NULL,                          /* exit thread */
    NULL,                          /* exit process */
    NULL,                          /* exit master */
    NGX_MODULE_V1_PADDING
};

static ngx_int_t
ngx_http_hello_handler(ngx_http_request_t *r)
{
    ngx_buf_t    *b;
    ngx_chain_t   out;
    ngx_str_t     response = ngx_string("Hello, Nginx Module!");

    r->headers_out.content_type_len = sizeof("text/plain") - 1;
    r->headers_out.content_type.data = (u_char *) "text/plain";
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = response.len;

    if (r->method == NGX_HTTP_HEAD) {
        return ngx_http_send_header(r);
    }

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    out.buf = b;
    out.next = NULL;

    b->pos = response.data;
    b->last = response.data + response.len;
    b->memory = 1;
    b->last_buf = 1;

    ngx_http_send_header(r);
    return ngx_http_output_filter(r, &out);
}

static char *
ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t *clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_hello_handler;

    return NGX_CONF_OK;
}

使用自定义模块

nginx
server {
    listen 80;
    server_name example.com;
    
    location /hello {
        hello;
    }
}

通过了解和使用这些模块,您可以大大扩展 Nginx 的功能。接下来我们将学习安全配置的详细内容。 🧩