nginx ngx_stream_module(1) 指令详解
相关链接
一、目录
1.1 模块简介
-
ngx_stream_core_module:流核心模块,提供了处理TCP和UDP流量的基本功能。它允许Nginx作为TCP/UDP代理服务器,管理和转发网络连接。常用的指令包括
server
块用于定义监听的端口和后端服务器。 -
ngx_stream_access_module:访问控制模块,基于IP地址或网络段来限制对TCP/UDP服务的访问。通过
allow
和deny
指令,可以指定允许或拒绝哪些客户端访问特定的服务。 -
ngx_stream_geo_module:地理定位模块,允许根据客户端IP地址定义变量。它可以用于基于地理位置的访问控制或日志记录等场景,类似于HTTP模块中的
ngx_http_geo_module
。 -
ngx_stream_geoip_module:GeoIP支持模块,扩展了
ngx_stream_geo_module
的功能,通过MaxMind的GeoIP数据库识别客户端的地理位置信息(如国家、城市等)。这有助于实现更精确的访问控制和日志分析。 -
ngx_stream_js_module:JavaScript支持模块,允许在Nginx配置中使用JavaScript编写脚本。这对于处理复杂的TCP/UDP流量逻辑非常有用,例如动态路由、访问控制等。
-
ngx_stream_keyval_module:键值对变量模块,提供了一种机制来存储和检索键值对数据。可以在不同的请求之间共享状态信息,适用于需要跨请求维护状态的应用场景,如会话管理或用户跟踪。
-
ngx_stream_limit_conn_module:连接限制模块,允许根据定义的条件(如IP地址)限制并发连接数。这对于防止资源耗尽攻击(如SYN Flood攻击)非常有用,通过设置合理的连接数上限,保护服务器免受过度负载的影响。
-
ngx_stream_log_module:日志记录模块,负责记录TCP/UDP请求的各种信息到日志文件中。通过自定义日志格式,可以记录诸如客户端IP、连接时间、协议类型等信息,这对于监控和调试非常重要。
-
ngx_stream_map_module:映射模块,可以根据输入变量创建新的变量。常用于条件判断和变量转换,例如将客户端IP地址映射为地理位置信息,或者基于某些条件设置响应头。这种灵活性有助于实现复杂的行为逻辑。
-
ngx_stream_mqtt_preread_module:MQTT预读模块,允许在不终止连接的情况下读取MQTT协议的消息头部信息。这对于需要在建立完整连接之前进行消息过滤或认证的场景非常有用。
-
ngx_stream_mqtt_filter_module:MQTT过滤模块,提供了对MQTT协议消息的高级处理能力。可以用于消息路由、内容过滤、协议转换等操作,使得Nginx能够作为MQTT消息代理使用。
1.2 指令目录
1.2.69 ngx_stream_core_module
- listen
- preread_buffer_size
- preread_timeout
- proxy_protocol_timeout
- resolver
- resolver_timeout
- server
- server_name
- server_names_hash_bucket_size
- server_names_hash_max_size
- stream
- tcp_nodelay
- variables_hash_bucket_size
- variables_hash_max_size
1.2.70 ngx_stream_access_module
1.2.71 ngx_stream_geo_module
1.2.72 ngx_stream_geoip_module
1.2.73 ngx_stream_js_module
- js_access
- js_context_reuse
- js_engine
- js_fetch_buffer_size
- js_fetch_ciphers
- js_fetch_max_response_buffer_size
- js_fetch_protocols
- js_fetch_timeout
- js_fetch_trusted_certificate
- js_fetch_verify
- js_fetch_verify_depth
- js_filter
- js_import
- js_include
- js_path
- js_periodic
- js_preload_object
- js_preread
- js_set
- js_shared_dict_zone
- js_var
1.2.74 ngx_stream_keyval_module
1.2.75 ngx_stream_limit_conn_module
1.2.76 ngx_stream_log_module
1.2.77 ngx_stream_map_module
1.2.78 ngx_stream_mqtt_preread_module
1.2.79 ngx_stream_mqtt_filter_module
二、解释
2.69 ngx_stream_core_module
ngx_stream_core_module 是 Nginx 的一个模块,用于处理基于 TCP 和 UDP 协议的流量。它允许你配置反向代理、负载均衡和会话持久化等功能,不仅限于 HTTP 流量,还可以应用于其他协议,如数据库连接、邮件服务器等。
主要功能
- TCP/UDP 代理:支持 TCP 和 UDP 流量的代理。
- 负载均衡:可以将流量分发到多个后端服务器,支持多种负载均衡算法(如轮询、最少连接、哈希等)。
- 会话持久化:通过 IP 哈希等方式实现会话持久化,确保同一客户端的请求总是被分配到同一个后端服务器。
- 健康检查:支持对后端服务器进行健康检查,自动剔除不可用的服务器。
常用指令
以下是与 ngx_stream_core_module
模块相关的常用配置指令及其简要说明:
-
stream
:定义流上下文,包含所有 TCP/UDP 相关的配置。 -
upstream
:定义一组后端服务器,支持负载均衡和健康检查。 -
server
:定义监听的地址和端口,并指定如何处理接收到的流量。 -
proxy_pass
:指定后端服务器或上游服务器组。 -
hash
:基于哈希值进行会话持久化。 -
least_conn
:使用最少连接算法进行负载均衡。 -
health_check
:启用健康检查,监控后端服务器的状态。
使用示例
以下是一些具体的配置示例,展示如何利用 ngx_stream_core_module
来实现各种功能。
基本配置 - TCP 代理
假设你想将所有到达 192.168.1.1:12345
的 TCP 流量代理到后端服务器组:
stream {
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
proxy_pass backend_servers;
}
}
在这个例子中:
upstream backend_servers { ... }
定义了一个后端服务器组,包含两台服务器。server { ... }
定义了一个监听在12345
端口的服务,所有到达该端口的流量会被代理到backend_servers
组中的服务器。
配置 - 负载均衡
你可以使用不同的负载均衡算法来分配流量。例如,使用最少连接算法:
stream {
upstream backend_servers {
least_conn; # 使用最少连接算法
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
proxy_pass backend_servers;
}
}
在这个例子中:
least_conn;
启用了最少连接算法,Nginx 会将新请求分配给当前连接数最少的服务器。
配置 - 会话持久化
为了确保同一客户端的请求总是被分配到同一个后端服务器,可以使用 IP 哈希算法:
stream {
upstream backend_servers {
hash $remote_addr consistent; # 使用 IP 哈希算法
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
proxy_pass backend_servers;
}
}
在这个例子中:
hash $remote_addr consistent;
使用客户端 IP 地址进行哈希计算,确保同一客户端的请求总是被分配到同一个后端服务器。
配置 - UDP 代理
除了 TCP 代理,ngx_stream_core_module
还支持 UDP 流量的代理。例如,将 DNS 请求代理到多个 DNS 服务器:
stream {
upstream dns_servers {
server dns1.example.com:53;
server dns2.example.com:53;
}
server {
listen 53 udp;
proxy_pass dns_servers;
proxy_timeout 200ms;
proxy_responses 1;
}
}
在这个例子中:
listen 53 udp;
表示监听在53
端口上的 UDP 流量。proxy_timeout 200ms;
设置了代理超时时间为 200 毫秒。proxy_responses 1;
表示每个请求只需要一个响应。
配置 - 健康检查
为了确保后端服务器的可用性,可以启用健康检查:
stream {
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
health_check interval=10 fails=3 passes=2; # 启用健康检查
}
server {
listen 12345;
proxy_pass backend_servers;
}
}
在这个例子中:
health_check interval=10 fails=3 passes=2;
启用了健康检查,默认情况下每 10 秒检查一次,连续失败 3 次即认为服务器不可用,连续成功 2 次即认为服务器恢复可用。
注意事项
-
性能考虑:
- 根据实际需求选择合适的负载均衡算法和会话持久化策略,避免不必要的资源浪费。
- 对于高并发场景,合理设置超时时间和重试机制,减少延迟和资源消耗。
-
安全性:
- 确保后端服务器的安全性,避免未经授权的访问。
- 对敏感数据进行加密传输,防止中间人攻击。
-
日志记录:
- 合理配置日志级别和格式,便于监控和故障排查。特别是注意记录与流量代理和负载均衡相关的错误信息和性能指标。
2.69.1 指令列表
listen
preread_buffer_size
preread_buffer_size 指令用于设置在处理 TCP/UDP 连接时预先读取数据的缓冲区大小。这有助于优化数据预读取性能。
Syntax: preread_buffer_size size;
Default: preread_buffer_size 16k;
Context: stream, server
This directive appeared in version 1.11.5.
size
:预先读取数据的缓冲区大小,默认为 16 KB。
案例
基本用法
最简单的 preread_buffer_size
用法是指定缓冲区大小:
stream {
upstream backend {
server 192.168.1.1:12345;
}
server {
listen 12345;
proxy_pass backend;
# 设置预读取缓冲区大小为 32 KB
preread_buffer_size 32k;
}
}
在这个例子中:
- 当 Nginx 处理到
backend
的连接时,将使用 32 KB 的缓冲区来预先读取数据。
注意事项
- 性能优化:合理的缓冲区大小可以减少 I/O 操作次数,提高处理效率,特别是在处理大数据量请求时。
- 内存使用:注意不要设置过大的缓冲区大小,以免占用过多内存。
preread_timeout
preread_timeout 指令用于设置在处理 TCP/UDP 连接时预先读取数据的超时时间。这有助于防止长时间等待导致的性能问题。
Syntax: preread_timeout timeout;
Default: preread_timeout 30s;
Context: stream, server
This directive appeared in version 1.11.5.
timeout
:预先读取数据的超时时间,默认为 30 秒。
案例
基本用法
最简单的 preread_timeout
用法是指定超时时间:
stream {
upstream backend {
server 192.168.1.1:12345;
}
server {
listen 12345;
proxy_pass backend;
# 设置预读取超时时间为 15 秒
preread_timeout 15s;
}
}
在这个例子中:
- 当 Nginx 在处理到
backend
的连接时,如果在 15 秒内未能完成数据的预先读取,将会超时并返回错误。
注意事项
- 性能影响:过长的超时时间可能导致请求延迟,过短的超时时间可能导致频繁失败。
- 可靠性:确保上游服务器的响应速度,以避免不必要的超时。
proxy_protocol_timeout
proxy_protocol_timeout 指令用于设置处理 PROXY 协议头信息的超时时间。PROXY 协议用于在 TCP 连接上传输客户端的真实 IP 地址等信息。
Syntax: proxy_protocol_timeout timeout;
Default: proxy_protocol_timeout 30s;
Context: stream, server
This directive appeared in version 1.11.4.
timeout
:处理 PROXY 协议头信息的超时时间,默认为 30 秒。
案例
基本用法
最简单的 proxy_protocol_timeout
用法是指定超时时间:
stream {
upstream backend {
server 192.168.1.1:12345;
}
server {
listen 12345 proxy_protocol;
proxy_pass backend;
# 设置处理 PROXY 协议头信息的超时时间为 20 秒
proxy_protocol_timeout 20s;
}
}
在这个例子中:
- 当 Nginx 使用 PROXY 协议处理到
backend
的连接时,如果在 20 秒内未能完成 PROXY 协议头信息的处理,将会超时并返回错误。
注意事项
- 性能影响:过长的超时时间可能导致请求延迟,过短的超时时间可能导致频繁失败。
- 兼容性:确保上游服务器支持并正确配置了 PROXY 协议,以避免通信问题。
resolver
resolver_timeout
server
server_name
server_names_hash_bucket_size
server_names_hash_max_size
stream
stream 指令块用于定义处理 TCP 和 UDP 流量的配置。Nginx 可以作为反向代理或负载均衡器来处理这些流量。
Syntax: stream { ... }
Default: —
Context: main
案例
基本用法
一个典型的 stream
配置示例如下:
stream {
upstream backend_tcp {
server 192.168.1.1:12345;
server 192.168.1.2:12345;
}
upstream backend_udp {
server 192.168.1.1:54321;
server 192.168.1.2:54321;
}
server {
listen 12345;
proxy_pass backend_tcp;
# 设置预读取缓冲区大小为 32 KB
preread_buffer_size 32k;
# 设置预读取超时时间为 15 秒
preread_timeout 15s;
# 设置处理 PROXY 协议头信息的超时时间为 20 秒
proxy_protocol_timeout 20s;
}
server {
listen 54321 udp;
proxy_pass backend_udp;
# 设置预读取缓冲区大小为 64 KB
preread_buffer_size 64k;
# 设置预读取超时时间为 10 秒
preread_timeout 10s;
# 设置处理 PROXY 协议头信息的超时时间为 25 秒
proxy_protocol_timeout 25s;
}
}
在这个例子中:
- 定义了两个上游服务器组
backend_tcp
和backend_udp
,分别处理 TCP 和 UDP 流量。 - 对于 TCP 流量:
- 监听端口 12345 并将流量代理到
backend_tcp
。 - 设置预读取缓冲区大小为 32 KB。
- 设置预读取超时时间为 15 秒。
- 设置处理 PROXY 协议头信息的超时时间为 20 秒。
- 监听端口 12345 并将流量代理到
- 对于 UDP 流量:
- 监听端口 54321 并将流量代理到
backend_udp
。 - 设置预读取缓冲区大小为 64 KB。
- 设置预读取超时时间为 10 秒。
- 设置处理 PROXY 协议头信息的超时时间为 25 秒。
- 监听端口 54321 并将流量代理到
注意事项
- 流量类型:根据实际需求选择适当的流量类型(TCP 或 UDP),并进行相应的配置。
- 负载均衡:结合其他负载均衡策略(如轮询、哈希等),确保流量合理分配到各个后端服务器。
- 监控与日志:启用适当的日志记录和监控机制,以便及时发现和解决问题。
tcp_nodelay
variables_hash_bucket_size
variables_hash_max_size
2.70 ngx_stream_access_module
ngx_stream_access_module 是 Nginx 的一个模块,用于在流(stream)上下文中实现访问控制。这个模块允许你基于客户端的 IP 地址、网络或特定的地址范围来允许或拒绝连接请求。它通常用于 TCP 和 UDP 代理服务中,以增强安全性。
主要功能
- IP 访问控制:根据客户端的 IP 地址或地址范围允许或拒绝连接。
- 网络访问控制:根据客户端所在的网络段允许或拒绝连接。
- 优先级处理:允许和拒绝规则按照配置文件中的顺序进行处理,先匹配到的规则优先生效。
使用示例
以下是一些简化的配置示例,展示了如何使用 ngx_stream_access_module
来实现访问控制。
基本访问控制
假设你希望仅允许来自 192.168.1.0/24
网络段的客户端连接到你的 TCP 服务:
stream {
upstream backend {
server backend.example.com:12345;
}
server {
listen 12345;
proxy_pass backend;
# 允许 192.168.1.0/24 网络段的客户端
allow 192.168.1.0/24;
# 拒绝所有其他客户端
deny all;
}
}
在这个例子中:
allow 192.168.1.0/24;
允许来自192.168.1.0/24
网络段的所有客户端连接。deny all;
拒绝所有其他客户端的连接。
多段网络访问控制
假设你希望允许来自多个网络段的客户端连接,并拒绝其他所有客户端:
stream {
upstream backend {
server backend.example.com:12345;
}
server {
listen 12345;
proxy_pass backend;
# 允许多个网络段的客户端
allow 192.168.1.0/24;
allow 10.0.0.0/8;
# 拒绝所有其他客户端
deny all;
}
}
在这个例子中:
allow 192.168.1.0/24;
和allow 10.0.0.0/8;
允许来自这两个网络段的所有客户端连接。deny all;
拒绝所有其他客户端的连接。
允许单个 IP 地址
假设你希望仅允许某个特定 IP 地址的客户端连接:
stream {
upstream backend {
server backend.example.com:12345;
}
server {
listen 12345;
proxy_pass backend;
# 允许单个 IP 地址
allow 192.168.1.100;
# 拒绝所有其他客户端
deny all;
}
}
在这个例子中:
allow 192.168.1.100;
允许来自192.168.1.100
这个特定 IP 地址的客户端连接。deny all;
拒绝所有其他客户端的连接。
注意事项
-
顺序优先:
allow
和deny
规则按照配置文件中的顺序进行处理。一旦匹配到一条规则,后续规则将不再处理。因此,确保规则的顺序正确非常重要。 -
性能影响:虽然访问控制规则对性能的影响较小,但在高并发环境中,仍然需要注意避免过多复杂的规则导致性能下降。
-
安全性:确保只允许可信的 IP 地址或网络段连接到你的服务。不要随意开放访问权限,尤其是在暴露于互联网的服务上。
-
日志记录:为了方便调试和监控,建议启用详细的日志记录,特别是在配置访问控制时。
error_log /var/log/nginx/error.log warn; access_log /var/log/nginx/access.log main;
2.70.1 指令列表
allow
deny
2.71 ngx_stream_geo_module
ngx_stream_geo_module 是 Nginx 的一个模块,用于在流(stream)上下文中根据客户端的 IP 地址进行地理定位。这个模块允许你基于客户端的地理位置信息来设置变量,并在后续处理中使用这些变量,例如路由、访问控制和日志记录等。
主要功能
- IP 地址到地理位置的映射:根据客户端的 IP 地址查询其地理位置信息。
- 变量设置:将查询结果存储在 Nginx 变量中,供其他模块或配置使用。
- 灵活配置:支持从文件或特定的变量值中加载地理位置数据库。
使用示例
以下是一些具体的配置示例,展示了如何使用 ngx_stream_geo_module
来根据客户端的 IP 地址设置变量。
基本配置
假设你想根据客户端的 IP 地址设置一个变量 $geo_var
,并将其用于后续处理:
stream {
# 定义地理定位块
geo $geo_var {
default unknown;
192.168.1.0/24 internal_network;
203.0.113.5 specific_client;
}
server {
listen 12345;
proxy_pass backend_server;
# 根据地理定位变量设置不同的代理服务器
if ($geo_var = internal_network) {
proxy_pass backend_internal;
}
if ($geo_var = specific_client) {
proxy_pass backend_special;
}
}
}
在这个例子中:
geo $geo_var { ... }
定义了一个地理定位块,设置了默认值和特定 IP 范围及单个 IP 地址的值。- 在
server
块中,根据$geo_var
的值选择不同的后端服务器进行代理。
包含外部地理数据文件
你可以将地理数据存储在一个单独的文件中,并通过 include
指令加载这些数据:
stream {
# 定义地理定位块
geo $geo_var {
default unknown;
include /etc/nginx/geo_data.txt;
}
server {
listen 12345;
proxy_pass backend_server;
# 根据地理定位变量设置不同的代理服务器
if ($geo_var = internal_network) {
proxy_pass backend_internal;
}
if ($geo_var = specific_client) {
proxy_pass backend_special;
}
}
}
其中 /etc/nginx/geo_data.txt
文件的内容可能如下:
192.168.1.0/24 internal_network;
203.0.113.5 specific_client;
结合负载均衡
假设你的应用部署在多个后端服务器上,并希望通过地理定位来选择合适的后端服务器:
stream {
upstream backend_usa {
server backend_usa_1.example.com;
server backend_usa_2.example.com;
}
upstream backend_eu {
server backend_eu_1.example.com;
server backend_eu_2.example.com;
}
# 定义地理定位块
geo $geo_var {
default eu;
include /etc/nginx/geo_data.txt;
}
server {
listen 12345;
# 根据地理定位变量选择不同的上游服务器组
if ($geo_var = usa) {
proxy_pass backend_usa;
}
if ($geo_var = eu) {
proxy_pass backend_eu;
}
}
}
在这个例子中:
upstream backend_usa { ... }
和upstream backend_eu { ... }
定义了两个不同的上游服务器组。geo $geo_var { ... }
根据客户端的 IP 地址设置变量$geo_var
。- 在
server
块中,根据$geo_var
的值选择不同的上游服务器组进行代理。
注意事项
- 地理数据更新:确保定期更新地理数据文件,以保持最新的地理位置信息。可以使用 MaxMind GeoLite2 或类似的免费或商业服务来获取最新的数据。
- 性能优化:尽量减少地理数据文件的大小,并避免过多的条件判断,以提高性能。
- 安全性:确保地理数据文件的安全性,防止未经授权的访问。可以设置适当的文件权限,并考虑加密敏感数据。
- 测试验证:在部署之前进行全面测试,确保所有配置按预期工作,并检查是否有任何潜在的问题(如 IP 地址未正确匹配、变量值错误等)。
2.71.1 指令列表
geo
2.72 ngx_stream_geoip_module
ngx_stream_geoip_module 是 Nginx 的一个模块,用于在处理 TCP 和 UDP 流量时根据客户端的 IP 地址进行地理定位。这个模块依赖于 MaxMind 的 GeoIP 数据库,可以用来实现基于地理位置的流量控制、访问限制和日志记录等功能。
主要功能
- 地理定位:根据客户端 IP 地址获取其地理位置信息(如国家、城市、经纬度等)。
- 流量控制:基于地理位置信息对流量进行控制或重定向。
- 访问限制:根据地理位置限制某些 IP 地址段的访问。
- 日志记录:将地理位置信息添加到日志中,便于分析和监控。
常用指令
以下是与 ngx_stream_geoip_module
模块相关的常用配置指令及其简要说明:
-
geoip_country
:加载指定的 GeoIP 国家数据库文件。 -
geoip_city
:加载指定的 GeoIP 城市数据库文件。 -
$geoip_country_code
:客户端所在国家的 ISO 3166-1 两位字母代码。 -
$geoip_country_name
:客户端所在国家的名称。 -
$geoip_city_country_code
:客户端所在城市的国家代码(当使用城市数据库时)。 -
$geoip_city_country_name
:客户端所在城市的国家名称(当使用城市数据库时)。 -
$geoip_city
:客户端所在城市的名称(当使用城市数据库时)。 -
$geoip_latitude
和$geoip_longitude
:客户端的地理坐标(当使用城市数据库时)。
使用示例
以下是一些具体的配置示例,展示如何利用 ngx_stream_geoip_module
来实现基于地理位置的功能。
基本配置 - 加载 GeoIP 数据库
首先,你需要下载并加载 MaxMind 的 GeoIP 数据库文件。可以从 MaxMind 下载免费版本的 GeoLite2 数据库。
假设你已经下载了 GeoLite2-Country.mmdb 和 GeoLite2-City.mmdb 文件,并将其放置在 /etc/nginx/geoip/
目录下。
stream {
# 加载 GeoIP 国家数据库
geoip_country /etc/nginx/geoip/GeoLite2-Country.mmdb;
# 加载 GeoIP 城市数据库
geoip_city /etc/nginx/geoip/GeoLite2-City.mmdb;
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
# 根据客户端 IP 地址获取地理位置信息
set $country_code $geoip_country_code;
set $country_name $geoip_country_name;
set $city_name $geoip_city;
set $latitude $geoip_latitude;
set $longitude $geoip_longitude;
proxy_pass backend_servers;
# 记录地理位置信息到日志
access_log /var/log/nginx/access.log combined_geoip;
}
}
在这个例子中:
geoip_country /etc/nginx/geoip/GeoLite2-Country.mmdb;
加载了国家级别的 GeoIP 数据库。geoip_city /etc/nginx/geoip/GeoLite2-City.mmdb;
加载了城市级别的 GeoIP 数据库。set $country_code $geoip_country_code;
等语句将地理位置信息存储在变量中,供后续使用。access_log /var/log/nginx/access.log combined_geoip;
将地理位置信息记录到日志中。
配置 - 基于地理位置的流量控制
假设你想根据客户端的地理位置来控制流量,例如禁止某些国家的用户访问:
stream {
geoip_country /etc/nginx/geoip/GeoLite2-Country.mmdb;
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
map $geoip_country_code $allowed_country {
default yes;
CN no; # 禁止中国(CN)的用户访问
RU no; # 禁止俄罗斯(RU)的用户访问
}
server {
listen 12345;
if ($allowed_country = no) {
return 403; # 如果不允许访问,返回 403 错误
}
proxy_pass backend_servers;
}
}
在这个例子中:
map $geoip_country_code $allowed_country { ... }
定义了一个映射,根据国家代码设置$allowed_country
变量的值。if ($allowed_country = no)
检查$allowed_country
变量的值,如果为no
则返回 403 错误。
配置 - 日志记录地理位置信息
你可以通过自定义日志格式将地理位置信息记录到日志中,以便后续分析:
stream {
geoip_country /etc/nginx/geoip/GeoLite2-Country.mmdb;
geoip_city /etc/nginx/geoip/GeoLite2-City.mmdb;
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
log_format combined_geoip '$remote_addr [$time_local] '
'"$protocol" $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$geoip_country_code" "$geoip_city"';
server {
listen 12345;
proxy_pass backend_servers;
access_log /var/log/nginx/access.log combined_geoip;
}
}
在这个例子中:
log_format combined_geoip ...
定义了一个新的日志格式combined_geoip
,其中包括地理位置信息。access_log /var/log/nginx/access.log combined_geoip;
使用自定义的日志格式记录日志。
注意事项
-
数据库更新:
- 定期更新 GeoIP 数据库以确保数据的准确性。MaxMind 提供了定期更新的服务,建议设置自动更新机制。
-
性能考虑:
- 在高并发场景下,频繁查询地理位置信息可能会影响性能。可以通过缓存或其他优化手段减少查询次数。
-
安全性:
- 确保 GeoIP 数据库的安全性,避免未经授权的访问。
- 对敏感数据进行加密传输,防止中间人攻击。
-
日志记录:
- 合理配置日志级别和格式,便于监控和故障排查。特别是注意记录与地理位置相关的错误信息和访问情况。
2.72.1 指令列表
geoip_country
geoip_city
geoip_org
2.73 ngx_stream_js_module
ngx_stream_js_module 是 Nginx 的一个模块,允许你在流(stream)上下文中使用 JavaScript 脚本来处理 TCP 和 UDP 连接。这个模块扩展了 Nginx 的功能,使你能够编写复杂的逻辑来控制连接的行为,例如访问控制、负载均衡决策、日志记录等。
主要功能
- JavaScript 脚本支持:在 Nginx 流配置中嵌入和执行 JavaScript 代码。
- 事件驱动的 API:提供了多种事件钩子,如
remoteAddr
,protocol
,serverPort
,clientPort
等,用于处理连接的不同阶段。 - 动态控制:通过 JavaScript 脚本实现动态的流量控制和处理逻辑。
使用示例
以下是一些简化的配置示例,展示了如何使用 ngx_stream_js_module
来实现不同的功能。
基本访问控制
假设你希望根据客户端 IP 地址来决定是否允许连接:
stream {
js_include /etc/nginx/scripts/access_control.js;
upstream backend {
server backend.example.com:12345;
}
server {
listen 12345;
proxy_pass backend;
js_on_access allow_connect;
}
}
对应的 access_control.js
文件内容:
function allow_connect(session) {
var clientIp = session.remoteAddress;
if (clientIp.startsWith('192.168.1.')) {
session.log("Allowing connection from " + clientIp);
return ngx.OK;
} else {
session.log("Denying connection from " + clientIp);
return ngx.DENY;
}
}
在这个例子中:
js_include
指令包含了外部的 JavaScript 文件/etc/nginx/scripts/access_control.js
。js_on_access allow_connect;
指定了在连接建立时调用allow_connect
函数。allow_connect
函数根据客户端 IP 地址决定是否允许连接。
日志记录
假设你希望记录每个连接的详细信息:
stream {
js_include /etc/nginx/scripts/log_connections.js;
upstream backend {
server backend.example.com:12345;
}
server {
listen 12345;
proxy_pass backend;
js_on_access log_connection;
}
}
对应的 log_connections.js
文件内容:
function log_connection(session) {
var clientIp = session.remoteAddress;
var serverIp = session.serverAddr;
var clientPort = session.clientPort;
var serverPort = session.serverPort;
session.log("Connection from " + clientIp + ":" + clientPort + " to " + serverIp + ":" + serverPort);
return ngx.OK;
}
在这个例子中:
log_connection
函数记录每个连接的源 IP 地址、源端口、目标 IP 地址和目标端口。
负载均衡决策
假设你希望通过 JavaScript 实现自定义的负载均衡策略:
stream {
js_include /etc/nginx/scripts/load_balancer.js;
upstream backend {
server backend1.example.com:12345;
server backend2.example.com:12345;
server backend3.example.com:12345;
}
server {
listen 12345;
proxy_pass backend;
js_on_access choose_backend;
}
}
对应的 load_balancer.js
文件内容:
function choose_backend(session) {
var clientIp = session.remoteAddress;
var hash = ngx.hash(clientIp);
// 根据哈希值选择后端服务器
var backendIndex = hash % 3;
session.backend = backendIndex;
session.log("Selected backend index: " + backendIndex);
return ngx.OK;
}
在这个例子中:
choose_backend
函数根据客户端 IP 地址计算哈希值,并根据哈希值选择后端服务器。
数据过滤
假设你希望通过 JavaScript 对传输的数据进行过滤或修改:
stream {
js_include /etc/nginx/scripts/data_filter.js;
upstream backend {
server backend.example.com:12345;
}
server {
listen 12345;
proxy_pass backend;
js_filter modify_data;
}
}
对应的 data_filter.js
文件内容:
function modify_data(data, flags) {
var modifiedData = data.replace(/old_string/g, "new_string");
// 如果需要终止连接
// return ngx.STOP;
return modifiedData;
}
在这个例子中:
modify_data
函数对传输的数据进行字符串替换操作。
注意事项
-
性能影响:虽然 JavaScript 提供了强大的灵活性,但在高并发环境中,JavaScript 脚本可能会成为性能瓶颈。尽量保持脚本简洁高效,避免复杂的计算和不必要的循环。
-
调试与测试:在生产环境中部署前,务必进行充分的测试,确保 JavaScript 脚本按预期工作。可以使用工具如
curl
或其他网络工具来模拟连接请求。curl -v telnet://example.com:12345
-
安全性:确保 JavaScript 脚本不会暴露敏感信息或被恶意利用。例如,避免直接输出未经处理的日志信息,以免泄露内部细节。
-
错误处理:在 JavaScript 脚本中添加适当的错误处理机制,以防止意外情况导致服务中断。
2.73.1 指令列表
js_access
js_access 用于在 Nginx 的流(stream)模块中定义一个 JavaScript 函数或模块函数,该函数将在访问控制阶段执行。这允许你通过自定义逻辑来决定是否允许连接。
Syntax: js_access function | module.function;
Default: —
Context: stream, server
function
:指定要调用的 JavaScript 函数。module.function
:指定要调用的 JavaScript 模块中的函数。
案例
基本用法
最简单的 js_access
用法是指定一个 JavaScript 函数来进行访问控制:
stream {
js_include /etc/nginx/scripts/access_control.js;
server {
listen 12345;
js_access allow_connection; # 调用名为 'allow_connection' 的 JavaScript 函数
}
}
在这个例子中,假设 /etc/nginx/scripts/access_control.js
文件包含以下内容:
function allow_connection(req) {
// 简单的访问控制逻辑示例
if (req.remoteAddress === '192.168.1.100') {
return ngx.HTTP_OK;
} else {
return ngx.HTTP_FORBIDDEN;
}
}
使用模块函数
根据实际需求使用模块中的函数:
stream {
js_include /etc/nginx/scripts/module.js;
server {
listen 12345;
js_access myModule.checkAccess; # 调用模块 'myModule' 中的 'checkAccess' 函数
}
}
在这个例子中,假设 /etc/nginx/scripts/module.js
文件包含以下内容:
var myModule = {
checkAccess: function(req) {
// 更复杂的访问控制逻辑示例
if (req.remoteAddress.startsWith('192.168')) {
return ngx.HTTP_OK;
} else {
return ngx.HTTP_FORBIDDEN;
}
}
};
注意事项
- 安全性:确保访问控制逻辑安全可靠,避免未经授权的访问。
- 灵活性:通过 JavaScript 实现灵活的访问控制逻辑,适应不同的业务需求。
js_context_reuse
js_engine
js_fetch_buffer_size
js_fetch_ciphers
js_fetch_max_response_buffer_size
js_fetch_protocols
js_fetch_timeout
js_fetch_trusted_certificate
js_fetch_verify
js_fetch_verify_depth
js_filter
js_filter 用于在 Nginx 的流(stream)模块中定义一个 JavaScript 函数或模块函数,该函数将在数据过滤阶段执行。这允许你对传输的数据进行处理和修改。
Syntax: js_filter function | module.function;
Default: —
Context: stream, server
function
:指定要调用的 JavaScript 函数。module.function
:指定要调用的 JavaScript 模块中的函数。
案例
基本用法
最简单的 js_filter
用法是指定一个 JavaScript 函数来进行数据过滤:
stream {
js_include /etc/nginx/scripts/data_filter.js;
server {
listen 12345;
js_filter modify_data; # 调用名为 'modify_data' 的 JavaScript 函数
}
}
在这个例子中,假设 /etc/nginx/scripts/data_filter.js
文件包含以下内容:
function modify_data(data) {
// 简单的数据过滤逻辑示例
return data.replace(/badword/g, 'goodword');
}
使用模块函数
根据实际需求使用模块中的函数:
stream {
js_include /etc/nginx/scripts/module.js;
server {
listen 12345;
js_filter myModule.filterData; # 调用模块 'myModule' 中的 'filterData' 函数
}
}
在这个例子中,假设 /etc/nginx/scripts/module.js
文件包含以下内容:
var myModule = {
filterData: function(data) {
// 更复杂的数据过滤逻辑示例
return data.replace(/[^\w\s]/g, '');
}
};
注意事项
- 数据完整性:确保数据过滤逻辑不会破坏数据的完整性和正确性。
- 性能优化:合理设计数据过滤逻辑,避免不必要的性能开销。
js_import
js_include
js_path
js_periodic
js_preload_object
js_preread
js_preread 用于在 Nginx 的流(stream)模块中定义一个 JavaScript 函数或模块函数,该函数将在预读阶段执行。这允许你在处理请求之前对数据进行预处理。
Syntax: js_preread function | module.function;
Default: —
Context: stream, server
function
:指定要调用的 JavaScript 函数。module.function
:指定要调用的 JavaScript 模块中的函数。
案例
基本用法
最简单的 js_preread
用法是指定一个 JavaScript 函数来进行预读处理:
stream {
js_include /etc/nginx/scripts/preread.js;
server {
listen 12345;
js_preread preprocess_data; # 调用名为 'preprocess_data' 的 JavaScript 函数
}
}
在这个例子中,假设 /etc/nginx/scripts/preread.js
文件包含以下内容:
function preprocess_data(data) {
// 简单的预读处理逻辑示例
return data.toUpperCase();
}
使用模块函数
根据实际需求使用模块中的函数:
stream {
js_include /etc/nginx/scripts/module.js;
server {
listen 12345;
js_preread myModule.preRead; # 调用模块 'myModule' 中的 'preRead' 函数
}
}
在这个例子中,假设 /etc/nginx/scripts/module.js
文件包含以下内容:
var myModule = {
preRead: function(data) {
// 更复杂的预读处理逻辑示例
return JSON.stringify(JSON.parse(data));
}
};
注意事项
- 数据预处理:确保预读处理逻辑能够有效提升后续处理步骤的效率。
- 错误处理:合理处理可能出现的异常情况,确保系统的稳定性。
js_set
js_var
2.74 ngx_stream_keyval_module
ngx_stream_keyval_module 是 Nginx 的一个模块,用于在流(stream)上下文中根据键值对(key-value pairs)来设置变量。这个模块允许你基于特定的键值对条件动态地设置变量,并在后续处理中使用这些变量,例如路由、访问控制和日志记录等。
主要功能
- 键值对匹配:根据客户端连接中的某些属性(如 IP 地址、端口等)进行键值对匹配。
- 变量设置:将匹配结果存储在 Nginx 变量中,供其他模块或配置使用。
- 灵活配置:支持从文件或直接在配置文件中定义键值对。
使用示例
以下是一些具体的配置示例,展示了如何使用 ngx_stream_keyval_module
来根据键值对设置变量。
基本配置
假设你想根据客户端的 IP 地址设置一个变量 $client_type
,并将其用于后续处理:
stream {
# 定义键值对映射
keyval $client_type $remote_addr {
192.168.1.10 trusted;
203.0.113.5 untrusted;
}
server {
listen 12345;
proxy_pass backend_server;
# 根据键值对变量设置不同的代理服务器
if ($client_type = trusted) {
proxy_pass trusted_backend;
}
if ($client_type = untrusted) {
proxy_pass untrusted_backend;
}
}
}
在这个例子中:
keyval $client_type $remote_addr { ... }
定义了一个键值对映射,设置了默认值和特定 IP 地址的值。- 在
server
块中,根据$client_type
的值选择不同的后端服务器进行代理。
包含外部键值对数据文件
你可以将键值对数据存储在一个单独的文件中,并通过 include
指令加载这些数据:
stream {
# 定义键值对映射
keyval $client_type $remote_addr {
include /etc/nginx/keyval_data.txt;
}
server {
listen 12345;
proxy_pass backend_server;
# 根据键值对变量设置不同的代理服务器
if ($client_type = trusted) {
proxy_pass trusted_backend;
}
if ($client_type = untrusted) {
proxy_pass untrusted_backend;
}
}
}
其中 /etc/nginx/keyval_data.txt
文件的内容可能如下:
192.168.1.10 trusted;
203.0.113.5 untrusted;
结合负载均衡
假设你的应用部署在多个后端服务器上,并希望通过键值对来选择合适的后端服务器:
stream {
upstream trusted_backend {
server backend_trusted_1.example.com;
server backend_trusted_2.example.com;
}
upstream untrusted_backend {
server backend_untrusted_1.example.com;
server backend_untrusted_2.example.com;
}
# 定义键值对映射
keyval $client_type $remote_addr {
default untrusted;
include /etc/nginx/keyval_data.txt;
}
server {
listen 12345;
# 根据键值对变量选择不同的上游服务器组
if ($client_type = trusted) {
proxy_pass trusted_backend;
}
if ($client_type = untrusted) {
proxy_pass untrusted_backend;
}
}
}
在这个例子中:
upstream trusted_backend { ... }
和upstream untrusted_backend { ... }
定义了两个不同的上游服务器组。keyval $client_type $remote_addr { ... }
根据客户端的 IP 地址设置变量$client_type
。- 在
server
块中,根据$client_type
的值选择不同的上游服务器组进行代理。
注意事项
- 数据更新:确保定期更新键值对数据文件,以保持最新的信息。可以通过脚本自动化更新过程。
- 性能优化:尽量减少键值对数据文件的大小,并避免过多的条件判断,以提高性能。可以使用
keyval_zone
指令来定义共享内存区域,从而提高查找效率。 - 安全性:确保键值对数据文件的安全性,防止未经授权的访问。可以设置适当的文件权限,并考虑加密敏感数据。
- 测试验证:在部署之前进行全面测试,确保所有配置按预期工作,并检查是否有任何潜在的问题(如键值未正确匹配、变量值错误等)。
2.74.1 指令列表
keyval
keyval_zone
2.75 ngx_stream_limit_conn_module
ngx_stream_limit_conn_module 是 Nginx 的一个模块,用于限制每个定义的键(如客户端 IP 地址)的并发连接数。这个模块可以帮助你控制资源使用,防止过载,并保护你的服务器免受拒绝服务(DoS)攻击。
主要功能
- 并发连接限制:根据指定的键(如客户端 IP 地址、用户 ID 等)限制并发连接数。
- 共享内存区:使用共享内存区来存储状态信息,确保在多个工作进程之间共享限制信息。
- 自定义响应:当达到连接限制时,可以返回自定义的响应或错误页面。
常用指令
以下是与 ngx_stream_limit_conn_module
模块相关的常用配置指令及其简要说明:
-
limit_conn_zone
:定义用于存储状态信息的共享内存区,并指定使用的键。 -
limit_conn
:设置最大允许的并发连接数。 -
limit_conn_status
:设置当超过连接限制时返回的状态码(默认是503 Service Unavailable
)。 -
$variable
:用于生成键的变量,例如$remote_addr
(客户端 IP 地址)、$binary_remote_addr
(二进制格式的客户端 IP 地址)等。
使用示例
以下是一些具体的配置示例,展示如何利用 ngx_stream_limit_conn_module
来实现并发连接限制。
基本配置 - 限制每个客户端 IP 的并发连接数
假设你想限制每个客户端 IP 地址最多只能有 10 个并发连接:
stream {
# 定义共享内存区,使用 $binary_remote_addr 作为键
limit_conn_zone $binary_remote_addr zone=per_ip:10m;
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
# 设置每个客户端 IP 地址的最大并发连接数为 10
limit_conn per_ip 10;
proxy_pass backend_servers;
}
}
在这个例子中:
limit_conn_zone $binary_remote_addr zone=per_ip:10m;
定义了一个名为per_ip
的共享内存区,大小为 10MB,使用二进制格式的客户端 IP 地址作为键。limit_conn per_ip 10;
设置了每个客户端 IP 地址的最大并发连接数为 10。
配置 - 限制每个源地址段的并发连接数
如果你想根据 IP 地址段而不是单个 IP 地址进行限制,可以使用 map
指令来定义键:
stream {
# 使用 map 指令定义键,按 C 类子网划分
map $binary_remote_addr $subnet_key {
192.168.1.0/24 192.168.1;
192.168.2.0/24 192.168.2;
default other;
}
# 定义共享内存区,使用 $subnet_key 作为键
limit_conn_zone $subnet_key zone=subnet:10m;
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
# 设置每个 C 类子网的最大并发连接数为 50
limit_conn subnet 50;
proxy_pass backend_servers;
}
}
在这个例子中:
map $binary_remote_addr $subnet_key { ... }
使用map
指令将 IP 地址映射到不同的键值,这里按照 C 类子网划分。limit_conn_zone $subnet_key zone=subnet:10m;
定义了一个名为subnet
的共享内存区,使用$subnet_key
作为键。limit_conn subnet 50;
设置了每个 C 类子网的最大并发连接数为 50。
配置 - 自定义超过限制时的响应
你可以自定义当超过连接限制时返回的状态码和响应内容:
stream {
# 定义共享内存区,使用 $binary_remote_addr 作为键
limit_conn_zone $binary_remote_addr zone=per_ip:10m;
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
# 设置每个客户端 IP 地址的最大并发连接数为 10
limit_conn per_ip 10;
# 自定义超过限制时返回的状态码
limit_conn_status 429; # 返回 429 Too Many Requests
proxy_pass backend_servers;
}
}
在这个例子中:
limit_conn_status 429;
设置了当超过连接限制时返回的状态码为429 Too Many Requests
。
配置 - 组合多个条件
你可以组合多个条件来进一步细化连接限制策略。例如,根据不同的条件执行不同的操作:
stream {
# 定义共享内存区,使用 $binary_remote_addr 作为键
limit_conn_zone $binary_remote_addr zone=per_ip:10m;
limit_conn_zone $server_name zone=per_server:10m;
upstream backend_servers {
server backend1.example.com:12345;
server backend2.example.com:12345;
}
server {
listen 12345;
server_name example.com;
# 设置每个客户端 IP 地址的最大并发连接数为 10
limit_conn per_ip 10;
# 设置每个服务器名称的最大并发连接数为 100
limit_conn per_server 100;
proxy_pass backend_servers;
}
}
在这个例子中:
limit_conn_zone $binary_remote_addr zone=per_ip:10m;
和limit_conn_zone $server_name zone=per_server:10m;
分别定义了两个共享内存区,分别基于客户端 IP 地址和服务器名称。limit_conn per_ip 10;
和limit_conn per_server 100;
分别设置了每个客户端 IP 地址和每个服务器名称的最大并发连接数。
注意事项
-
性能考虑:
- 使用共享内存区时,确保其大小足够大以容纳所有可能的键值。如果内存不足,可能会导致部分连接被拒绝。
- 在高并发场景下,尽量简化键值的计算逻辑,避免复杂的嵌套和多次查询。
-
安全性:
- 确保对关键资源的访问限制合理,避免过度限制影响正常业务。
- 对敏感数据进行加密传输,防止中间人攻击。
-
日志记录:
- 合理配置日志级别和格式,便于监控和故障排查。特别是注意记录与连接限制相关的错误信息和访问情况。
2.75.1 指令列表
limit_conn
limit_conn_dry_run
limit_conn_log_level
limit_conn_zone
2.76 ngx_stream_log_module
ngx_stream_log_module 是 Nginx 的一个模块,用于记录流(stream)连接的日志。这个模块允许你配置详细的日志格式和日志文件路径,以便于监控和分析通过 Nginx 代理的 TCP 和 UDP 连接。
主要功能
- 自定义日志格式:你可以定义日志的格式,包括客户端 IP、端口、服务器 IP、端口、协议类型等。
- 多种日志级别:支持不同的日志级别(如
error
,warn
,info
等),可以根据需要调整日志输出的详细程度。 - 日志轮转:可以与日志轮转工具结合使用,避免日志文件过大。
使用示例
以下是一些简化的配置示例,展示了如何使用 ngx_stream_log_module
来实现不同的日志记录需求。
基本日志记录
假设你希望记录所有通过 Nginx 代理的 TCP 连接的基本信息:
stream {
upstream backend {
server backend.example.com:12345;
}
log_format custom_format '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';
server {
listen 12345;
proxy_pass backend;
access_log /var/log/nginx/stream_access.log custom_format;
}
}
在这个例子中:
log_format custom_format
定义了一个名为custom_format
的日志格式,包含客户端 IP 地址、时间、协议类型、状态码、发送和接收的字节数以及会话时长。access_log /var/log/nginx/stream_access.log custom_format;
指定了使用该日志格式记录访问日志。
记录更多详细信息
假设你希望记录更多的连接细节,例如客户端和服务器的端口号:
stream {
upstream backend {
server backend.example.com:12345;
}
log_format detailed_format '$remote_addr:$remote_port -> $server_addr:$server_port [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';
server {
listen 12345;
proxy_pass backend;
access_log /var/log/nginx/stream_access.log detailed_format;
}
}
在这个例子中:
log_format detailed_format
定义了一个更详细的日志格式,除了基本的信息外,还包含了客户端和服务器的端口号。
按条件记录日志
假设你希望根据某些条件来决定是否记录日志,例如仅记录特定来源 IP 地址的连接:
stream {
upstream backend {
server backend.example.com:12345;
}
log_format conditional_format '$remote_addr:$remote_port -> $server_addr:$server_port [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';
map $remote_addr $loggable {
default 0;
"~^192\.168\." 1;
}
server {
listen 12345;
proxy_pass backend;
access_log /var/log/nginx/stream_access.log conditional_format if=$loggable;
}
}
在这个例子中:
map
指令用于创建一个变量$loggable
,它根据客户端 IP 地址的值决定是否记录日志。access_log
指令中的if=$loggable
参数确保只有符合条件的连接才会被记录到日志文件中。
日志轮转
为了防止日志文件过大,可以结合日志轮转工具(如 logrotate
)进行管理。以下是 logrotate
配置的一个示例:
/var/log/nginx/stream_access.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0640 nginx nginx
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
在这个例子中:
daily
表示每天轮转一次日志。rotate 30
表示保留最近 30 天的日志文件。compress
和delaycompress
分别表示压缩旧日志文件,并延迟一天压缩前一天的日志文件。postrotate
和endscript
之间的内容会在每次轮转后执行,这里通过发送USR1
信号通知 Nginx 重新打开日志文件。
注意事项
-
性能影响:虽然日志记录对性能的影响较小,但在高并发环境中,频繁写入日志可能会导致 I/O 性能瓶颈。可以通过调整缓冲区大小(如
buffer=size
)和刷新时间(如flush=time
)来优化性能。 -
安全性:确保日志文件的权限设置正确,避免敏感信息泄露。通常情况下,日志文件应只允许管理员和 Nginx 用户读取和写入。
chown root:nginx /var/log/nginx/stream_access.log chmod 640 /var/log/nginx/stream_access.log
-
日志格式:合理设计日志格式,确保包含足够的信息以便于后续分析,同时避免不必要的字段以减少日志文件的大小。
-
日志轮转:建议定期轮转日志文件,以防止日志文件过大。可以使用
logrotate
或其他类似的工具来自动管理日志文件。
2.76.1 指令列表
access_log
log_format
open_log_file_cache
2.77 ngx_stream_map_module
ngx_stream_map_module 是 Nginx 的一个模块,用于在流(stream)上下文中根据指定的键(如客户端 IP 地址、端口等)创建映射表,并将这些键映射到特定的值。这个模块允许你基于映射结果设置变量,并在后续处理中使用这些变量,例如路由、访问控制和日志记录等。
主要功能
- 键值映射:根据指定的键创建映射表,并将这些键映射到特定的值。
- 变量设置:将映射结果存储在 Nginx 变量中,供其他模块或配置使用。
- 灵活配置:支持从文件或直接在配置文件中定义映射关系。
使用示例
以下是一些具体的配置示例,展示了如何使用 ngx_stream_map_module
来根据键值映射设置变量。
基本配置
假设你想根据客户端的 IP 地址设置一个变量 $client_type
,并将其用于后续处理:
stream {
# 定义映射块
map $remote_addr $client_type {
default untrusted;
192.168.1.10 trusted;
203.0.113.5 special;
}
server {
listen 12345;
proxy_pass backend_server;
# 根据映射变量设置不同的代理服务器
if ($client_type = trusted) {
proxy_pass trusted_backend;
}
if ($client_type = special) {
proxy_pass special_backend;
}
if ($client_type = untrusted) {
proxy_pass untrusted_backend;
}
}
}
在这个例子中:
map $remote_addr $client_type { ... }
定义了一个映射块,设置了默认值和特定 IP 地址的值。- 在
server
块中,根据$client_type
的值选择不同的后端服务器进行代理。
包含外部映射数据文件
你可以将映射数据存储在一个单独的文件中,并通过 include
指令加载这些数据:
stream {
# 定义映射块
map $remote_addr $client_type {
default untrusted;
include /etc/nginx/map_data.txt;
}
server {
listen 12345;
proxy_pass backend_server;
# 根据映射变量设置不同的代理服务器
if ($client_type = trusted) {
proxy_pass trusted_backend;
}
if ($client_type = special) {
proxy_pass special_backend;
}
if ($client_type = untrusted) {
proxy_pass untrusted_backend;
}
}
}
其中 /etc/nginx/map_data.txt
文件的内容可能如下:
192.168.1.10 trusted;
203.0.113.5 special;
结合负载均衡
假设你的应用部署在多个后端服务器上,并希望通过映射来选择合适的后端服务器:
stream {
upstream trusted_backend {
server backend_trusted_1.example.com;
server backend_trusted_2.example.com;
}
upstream special_backend {
server backend_special_1.example.com;
server backend_special_2.example.com;
}
upstream untrusted_backend {
server backend_untrusted_1.example.com;
server backend_untrusted_2.example.com;
}
# 定义映射块
map $remote_addr $client_type {
default untrusted;
include /etc/nginx/map_data.txt;
}
server {
listen 12345;
# 根据映射变量选择不同的上游服务器组
if ($client_type = trusted) {
proxy_pass trusted_backend;
}
if ($client_type = special) {
proxy_pass special_backend;
}
if ($client_type = untrusted) {
proxy_pass untrusted_backend;
}
}
}
在这个例子中:
upstream trusted_backend { ... }
,upstream special_backend { ... }
和upstream untrusted_backend { ... }
定义了三个不同的上游服务器组。map $remote_addr $client_type { ... }
根据客户端的 IP 地址设置变量$client_type
。- 在
server
块中,根据$client_type
的值选择不同的上游服务器组进行代理。
注意事项
- 数据更新:确保定期更新映射数据文件,以保持最新的信息。可以通过脚本自动化更新过程。
- 性能优化:
- 使用
map_hash_bucket_size
和map_hash_max_size
指令优化哈希表的内存使用。 - 尽量减少映射数据文件的大小,并避免过多的条件判断,以提高性能。
- 使用
- 安全性:确保映射数据文件的安全性,防止未经授权的访问。可以设置适当的文件权限,并考虑加密敏感数据。
- 测试验证:在部署之前进行全面测试,确保所有配置按预期工作,并检查是否有任何潜在的问题(如键未正确匹配、变量值错误等)。
2.77.1 指令列表
map
map_hash_bucket_size
map_hash_max_size
2.78 ngx_stream_mqtt_preread_module
ngx_stream_mqtt_preread_module 是 Nginx 的一个模块,专门用于处理 MQTT(Message Queuing Telemetry Transport)协议的流量。MQTT 是一种轻量级的消息协议,常用于物联网(IoT)设备之间的通信。该模块允许你在不完全解析 MQTT 消息的情况下读取和处理部分消息头信息,从而实现基于这些信息的路由、负载均衡等功能。
主要功能
- 预读 MQTT 消息头:在不完全解析 MQTT 消息的情况下,读取并处理 MQTT 消息头中的关键信息(如客户端 ID、用户名等)。
- 基于预读信息的路由:根据预读到的信息将连接路由到不同的后端服务器或上游组。
- 会话持久化:通过哈希算法确保同一客户端的请求总是被分配到同一个后端服务器。
常用指令
以下是与 ngx_stream_mqtt_preread_module
模块相关的常用配置指令及其简要说明:
-
mqtt_preread
:启用 MQTT 预读功能,并提取指定的字段(如客户端 ID、用户名等)。 -
$mqtt_preread_client_id
:预读到的 MQTT 客户端 ID。 -
$mqtt_preread_username
:预读到的 MQTT 用户名。 -
hash
:基于哈希值进行会话持久化。 -
proxy_pass
:指定后端服务器或上游服务器组。
使用示例
以下是一些具体的配置示例,展示如何利用 ngx_stream_mqtt_preread_module
来实现基于 MQTT 预读信息的功能。
基本配置 - 启用 MQTT 预读功能
假设你想启用 MQTT 预读功能,并根据客户端 ID 将连接路由到不同的后端服务器:
stream {
upstream backend_servers {
server backend1.example.com:1883;
server backend2.example.com:1883;
}
server {
listen 1883;
# 启用 MQTT 预读功能
mqtt_preread;
# 根据客户端 ID 进行哈希计算,实现会话持久化
hash $mqtt_preread_client_id consistent;
proxy_pass backend_servers;
}
}
在这个例子中:
mqtt_preread;
启用了 MQTT 预读功能。hash $mqtt_preread_client_id consistent;
使用客户端 ID 进行哈希计算,确保同一客户端的连接总是被分配到同一个后端服务器。proxy_pass backend_servers;
将流量代理到backend_servers
组中的服务器。
配置 - 基于用户名进行路由
如果你想根据 MQTT 用户名将连接路由到不同的后端服务器,可以这样做:
stream {
upstream backend_users {
server user_backend1.example.com:1883;
}
upstream backend_devices {
server device_backend1.example.com:1883;
}
server {
listen 1883;
# 启用 MQTT 预读功能
mqtt_preread;
# 根据用户名进行条件判断
if ($mqtt_preread_username = "user") {
proxy_pass backend_users;
}
if ($mqtt_preread_username = "device") {
proxy_pass backend_devices;
}
}
}
在这个例子中:
mqtt_preread;
启用了 MQTT 预读功能。if ($mqtt_preread_username = "user") { ... }
和if ($mqtt_preread_username = "device") { ... }
分别检查预读到的用户名,并根据用户名将连接路由到不同的后端服务器。
配置 - 记录预读信息到日志
你可以将预读到的 MQTT 信息记录到日志中,便于后续分析和监控:
stream {
upstream backend_servers {
server backend1.example.com:1883;
server backend2.example.com:1883;
}
log_format mqtt_log '$remote_addr [$time_local] '
'"$protocol" $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$mqtt_preread_client_id" "$mqtt_preread_username"';
server {
listen 1883;
# 启用 MQTT 预读功能
mqtt_preread;
# 设置日志格式
access_log /var/log/nginx/mqtt_access.log mqtt_log;
proxy_pass backend_servers;
}
}
在这个例子中:
mqtt_preread;
启用了 MQTT 预读功能。log_format mqtt_log ...
定义了一个新的日志格式mqtt_log
,其中包括预读到的 MQTT 客户端 ID 和用户名。access_log /var/log/nginx/mqtt_access.log mqtt_log;
使用自定义的日志格式记录日志。
配置 - 负载均衡和会话持久化
为了确保同一客户端的请求总是被分配到同一个后端服务器,可以使用哈希算法进行会话持久化:
stream {
upstream backend_servers {
server backend1.example.com:1883;
server backend2.example.com:1883;
}
server {
listen 1883;
# 启用 MQTT 预读功能
mqtt_preread;
# 根据客户端 ID 进行哈希计算,实现会话持久化
hash $mqtt_preread_client_id consistent;
proxy_pass backend_servers;
}
}
在这个例子中:
mqtt_preread;
启用了 MQTT 预读功能。hash $mqtt_preread_client_id consistent;
使用客户端 ID 进行哈希计算,确保同一客户端的连接总是被分配到同一个后端服务器。proxy_pass backend_servers;
将流量代理到backend_servers
组中的服务器。
注意事项
-
性能考虑:
- 在高并发场景下,尽量简化预读逻辑,避免复杂的嵌套和多次查询。
- 确保共享内存区大小足够大以容纳所有可能的键值。
-
安全性:
- 确保对敏感数据进行加密传输,防止中间人攻击。
- 对预读到的信息进行适当的验证和过滤,避免恶意输入。
-
日志记录:
- 合理配置日志级别和格式,便于监控和故障排查。特别是注意记录与 MQTT 预读相关的错误信息和访问情况。
2.78.1 指令列表
mqtt_preread
mqtt_preread 用于控制是否启用 MQTT 协议的预读功能。当启用时,Nginx 将在处理 MQTT 请求之前先读取部分数据进行预处理。
Syntax: mqtt_preread on | off;
Default: mqtt_preread off;
Context: stream, server
on
:启用 MQTT 预读功能。off
:禁用 MQTT 预读功能(默认值)。
案例
启用 MQTT 预读
最简单的 mqtt_preread
用法是启用 MQTT 预读功能:
stream {
server {
listen 1883;
mqtt_preread on; # 启用 MQTT 预读功能
}
}
禁用 MQTT 预读
根据实际需求禁用 MQTT 预读功能:
stream {
server {
listen 1883;
mqtt_preread off; # 禁用 MQTT 预读功能
}
}
注意事项
- 性能影响:启用 MQTT 预读可能会带来一定的性能开销,特别是在高并发场景下。
- 适用场景:适用于需要提前处理 MQTT 数据以优化后续处理步骤的场景。
2.79 ngx_stream_mqtt_filter_module
ngx_stream_mqtt_filter_module 是 Nginx 的一个扩展模块,旨在支持 MQTT(Message Queuing Telemetry Transport)协议的过滤和处理。MQTT 是一种轻量的消息协议,专为低带宽、高延迟或不可靠的网络设计,常用于物联网(IoT)设备之间的通信。
主要功能
- MQTT 协议支持:允许 Nginx 作为 MQTT 代理服务器,处理 MQTT 连接、发布和订阅消息。
- 访问控制:基于客户端 IP 地址或其他条件对 MQTT 连接进行访问控制。
- 日志记录:记录 MQTT 连接和消息传输的日志。
- 负载均衡:将 MQTT 连接分发到多个后端服务器,实现负载均衡。
- 消息过滤:可以在消息传递过程中对消息进行过滤和修改。
使用示例
以下是一些简化的配置示例,展示了如何使用 ngx_stream_mqtt_filter_module
来实现不同的 MQTT 功能。
基本 MQTT 代理
假设你希望将 MQTT 连接代理到后端服务器:
stream {
upstream mqtt_backend {
server backend.example.com:1883;
}
server {
listen 1883;
proxy_pass mqtt_backend;
# 配置 MQTT 代理
mqtt_pass mqtt_backend;
# 日志记录
mqtt_access_log /var/log/nginx/mqtt_access.log custom_format;
}
}
对应的日志格式定义:
log_format custom_format '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';
在这个例子中:
upstream mqtt_backend
定义了一个名为mqtt_backend
的后端服务器组。server { listen 1883; proxy_pass mqtt_backend; }
将监听在端口 1883 上的所有连接代理到后端服务器。mqtt_access_log /var/log/nginx/mqtt_access.log custom_format;
指定了使用自定义日志格式记录 MQTT 访问日志。
访问控制
假设你希望根据客户端 IP 地址来决定是否允许 MQTT 连接:
stream {
upstream mqtt_backend {
server backend.example.com:1883;
}
server {
listen 1883;
proxy_pass mqtt_backend;
# 允许特定 IP 范围的客户端
allow 192.168.1.0/24;
deny all;
# 日志记录
mqtt_access_log /var/log/nginx/mqtt_access.log custom_format;
}
}
在这个例子中:
allow 192.168.1.0/24;
允许来自192.168.1.0/24
网络段的所有客户端连接。deny all;
拒绝所有其他客户端的连接。
消息过滤
假设你希望通过 JavaScript 实现简单的消息过滤逻辑(需要结合 ngx_stream_js_module
):
首先确保 ngx_stream_js_module
已启用,并包含相关的 JavaScript 文件:
stream {
js_include /etc/nginx/scripts/mqtt_filter.js;
upstream mqtt_backend {
server backend.example.com:1883;
}
server {
listen 1883;
proxy_pass mqtt_backend;
# 日志记录
mqtt_access_log /var/log/nginx/mqtt_access.log custom_format;
# 消息过滤
js_on_preread filter_message;
}
}
对应的 mqtt_filter.js
文件内容:
function filter_message(session) {
var message = session.read();
// 假设我们只允许某些特定主题的消息通过
if (message.topic.startsWith("allowed/topic/")) {
session.write(message);
} else {
session.log("Denied message on topic: " + message.topic);
}
return ngx.OK;
}
在这个例子中:
js_on_preread filter_message;
在读取客户端数据之前调用filter_message
函数。filter_message
函数检查消息的主题,并仅允许特定主题的消息通过。
日志轮转
为了防止日志文件过大,可以结合日志轮转工具(如 logrotate
)进行管理。以下是 logrotate
配置的一个示例:
/var/log/nginx/mqtt_access.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0640 nginx nginx
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
在这个例子中:
daily
表示每天轮转一次日志。rotate 30
表示保留最近 30 天的日志文件。compress
和delaycompress
分别表示压缩旧日志文件,并延迟一天压缩前一天的日志文件。postrotate
和endscript
之间的内容会在每次轮转后执行,这里通过发送USR1
信号通知 Nginx 重新打开日志文件。
注意事项
-
性能影响:虽然日志记录和消息过滤对性能的影响较小,但在高并发环境中,频繁写入日志或复杂的过滤逻辑可能会导致 I/O 性能瓶颈。可以通过调整缓冲区大小(如
buffer=size
)和刷新时间(如flush=time
)来优化性能。 -
安全性:确保日志文件的权限设置正确,避免敏感信息泄露。通常情况下,日志文件应只允许管理员和 Nginx 用户读取和写入。
chown root:nginx /var/log/nginx/mqtt_access.log chmod 640 /var/log/nginx/mqtt_access.log
-
日志格式:合理设计日志格式,确保包含足够的信息以便于后续分析,同时避免不必要的字段以减少日志文件的大小。
-
日志轮转:建议定期轮转日志文件,以防止日志文件过大。可以使用
logrotate
或其他类似的工具来自动管理日志文件。
2.79.1 指令列表
mqtt
mqtt 指令用于启用或禁用MQTT协议的支持。这个指令帮助配置Nginx以处理MQTT协议的请求。
Syntax: mqtt on | off;
Default: mqtt off;
Context: stream, server
on
:启用MQTT协议支持。off
:禁用MQTT协议支持(默认值)。
案例
基本用法
最简单的 mqtt
用法是指定是否启用MQTT协议支持:
stream {
server {
listen 1883;
mqtt on;
proxy_pass backend_mqtt_broker;
}
}
在这个例子中:
- 设置了
mqtt on
,这意味着Nginx将启用MQTT协议支持并监听端口1883。
动态设置不同配置
你可以根据不同的服务器块动态设置是否启用MQTT协议支持:
stream {
server {
listen 1883;
mqtt on;
proxy_pass backend_mqtt_broker_1;
}
server {
listen 1884;
mqtt off;
proxy_pass backend_mqtt_broker_2;
}
}
在这个例子中:
- 对于监听端口1883的服务器块,设置了
mqtt on
。 - 对于监听端口1884的服务器块,设置了
mqtt off
。
注意事项
- 协议支持:确保在需要处理MQTT协议的环境中启用该功能,并根据需求进行配置。
- 适用场景:适用于需要处理MQTT协议的应用场景。例如,在物联网(IoT)应用、实时数据传输等环境中使用。
- 调试和监控:如果你遇到MQTT协议问题,可以检查以下几点:
- 确保MQTT协议支持设置合理,并符合你的需求。
- 查看Nginx的日志文件,确认是否有与此相关的警告或错误信息。
- 使用工具模拟不同负载条件下的请求进行测试,确保在各种情况下都能正常工作。
mqtt_buffers
mqtt_buffers 指令用于设置MQTT协议连接的缓冲区大小和数量。这个指令帮助优化MQTT消息的接收和发送性能。
Syntax: mqtt_buffers number size;
Default: mqtt_buffers 100 1k;
Context: stream, server
This directive appeared in version 1.25.1.
number
:指定缓冲区的数量。size
:指定每个缓冲区的大小,默认值为100 1k
(100个1KB的缓冲区)。
案例
基本用法
最简单的 mqtt_buffers
用法是指定具体的缓冲区数量和大小:
stream {
server {
listen 1883;
mqtt on;
mqtt_buffers 50 2k;
proxy_pass backend_mqtt_broker;
}
}
在这个例子中:
- 设置了
mqtt_buffers 50 2k
,这意味着Nginx将使用50个2KB的缓冲区来处理MQTT消息。
动态设置不同配置
你可以根据不同的服务器块动态设置不同的缓冲区数量和大小:
stream {
server {
listen 1883;
mqtt on;
mqtt_buffers 50 2k;
proxy_pass backend_mqtt_broker_1;
}
server {
listen 1884;
mqtt on;
mqtt_buffers 100 1k;
proxy_pass backend_mqtt_broker_2;
}
}
在这个例子中:
- 对于监听端口1883的服务器块,设置了
mqtt_buffers 50 2k
。 - 对于监听端口1884的服务器块,设置了
mqtt_buffers 100 1k
。
注意事项
- 性能与资源平衡:合理设置缓冲区数量和大小,避免过大导致内存占用过高或过小影响消息处理效率。
- 适用场景:适用于需要优化MQTT消息处理性能的应用场景。例如,在高并发的物联网应用中使用。
- 调试和监控:如果你遇到缓冲区问题,可以检查以下几点:
- 确保缓冲区设置合理,并符合你的需求。
- 查看Nginx的日志文件,确认是否有与此相关的警告或错误信息。
- 使用工具模拟不同负载条件下的请求进行测试,确保在各种情况下都能正常工作。
mqtt_rewrite_buffer_size
mqtt_rewrite_buffer_size 指令用于设置重写MQTT消息时使用的缓冲区大小。这个指令帮助优化MQTT消息的重写操作。
Syntax: mqtt_rewrite_buffer_size size;
Default: mqtt_rewrite_buffer_size 4k|8k;
Context: server
size
:指定重写缓冲区的大小,默认值为4k
或8k
。
案例
基本用法
最简单的 mqtt_rewrite_buffer_size
用法是指定具体的缓冲区大小:
server {
listen 1883;
mqtt on;
mqtt_rewrite_buffer_size 8k;
proxy_pass backend_mqtt_broker;
}
在这个例子中:
- 设置了
mqtt_rewrite_buffer_size 8k
,这意味着Nginx将使用8KB的缓冲区来进行MQTT消息的重写操作。
动态设置不同配置
由于 mqtt_rewrite_buffer_size
只能在 server
上下文中配置,因此不能针对不同的服务器块单独设置。你可以在主配置文件中统一设置:
server {
listen 1883;
mqtt on;
mqtt_rewrite_buffer_size 8k;
proxy_pass backend_mqtt_broker_1;
}
server {
listen 1884;
mqtt on;
mqtt_rewrite_buffer_size 4k;
proxy_pass backend_mqtt_broker_2;
}
在这个例子中:
- 对于监听端口1883的服务器块,设置了
mqtt_rewrite_buffer_size 8k
。 - 对于监听端口1884的服务器块,设置了
mqtt_rewrite_buffer_size 4k
。
注意事项
- 重写操作优化:合理设置重写缓冲区大小,避免过大导致内存占用过高或过小影响重写操作效率。
- 适用场景:适用于需要对MQTT消息进行重写的场景。例如,在需要修改或增强MQTT消息内容的应用中使用。
- 调试和监控:如果你遇到重写缓冲区问题,可以检查以下几点:
- 确保重写缓冲区大小设置合理,并符合你的需求。
- 查看Nginx的日志文件,确认是否有与此相关的警告或错误信息。
- 使用工具模拟不同负载条件下的请求进行测试,确保在各种情况下都能正常工作。
mqtt_set_connect
mqtt_set_connect 指令用于在MQTT连接建立时设置特定字段的值。这个指令帮助自定义MQTT连接的行为。
Syntax: mqtt_set_connect field value;
Default: —
Context: server
field
:指定要设置的字段名称。value
:指定字段的值。
案例
基本用法
最简单的 mqtt_set_connect
用法是指定具体的字段和值:
server {
listen 1883;
mqtt on;
mqtt_set_connect client_id my_custom_client_id;
proxy_pass backend_mqtt_broker;
}
在这个例子中:
- 设置了
mqtt_set_connect client_id my_custom_client_id
,这意味着Nginx将在MQTT连接建立时设置客户端ID为my_custom_client_id
。
动态设置不同配置
你可以根据不同的服务器块动态设置不同的字段和值:
server {
listen 1883;
mqtt on;
mqtt_set_connect client_id custom_client_id_1;
proxy_pass backend_mqtt_broker_1;
}
server {
listen 1884;
mqtt on;
mqtt_set_connect client_id custom_client_id_2;
proxy_pass backend_mqtt_broker_2;
}
在这个例子中:
- 对于监听端口1883的服务器块,设置了
mqtt_set_connect client_id custom_client_id_1
。 - 对于监听端口1884的服务器块,设置了
mqtt_set_connect client_id custom_client_id_2
。
注意事项
- 字段设置:合理设置需要自定义的字段及其值,确保符合实际应用场景的需求。
- 适用场景:适用于需要自定义MQTT连接行为的场景。例如,在需要统一管理客户端ID或其他连接属性的应用中使用。
- 调试和监控:如果你遇到字段设置问题,可以检查以下几点:
- 确保字段设置合理,并符合你的需求。
- 查看Nginx的日志文件,确认是否有与此相关的警告或错误信息。
- 使用工具模拟不同负载条件下的请求进行测试,确保在各种情况下都能正常工作。