- Upstream 模块源码实现分析(负载均衡算法、故障转移) - Stream 模块架构分析(TCP/UDP 代理处理流程) - Mail 模块架构概述(IMAP/POP3/SMTP 协议支持) - 事件模块源码架构(定时器、epoll、QUIC) - 变量系统源码实现(索引变量、前缀变量机制) 基于 nginx 1.31.0 源码分析 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
27 KiB
27 KiB
NGINX TCP/UDP Stream 模块指南
1. Stream 模块概述
Stream 模块提供 TCP/UDP 流处理功能,包括:
- TCP 代理与负载均衡
- UDP 代理(DNS、日志收集等)
- TLS/SSL 终端
- 基于 SNI 的路由
版本要求
- 自 1.9.0 版本可用
- 默认不构建,需编译时添加
--with-stream参数
配置上下文
stream {
# TCP/UDP 配置
server {
listen 12345;
proxy_pass backend:54321;
}
}
2. 基础配置示例
TCP 代理
stream {
upstream backend {
server 192.168.1.1:3306;
server 192.168.1.2:3306;
}
server {
listen 3306;
proxy_pass backend;
proxy_timeout 3s;
proxy_connect_timeout 1s;
}
}
UDP 代理
stream {
upstream dns_servers {
server 8.8.8.8:53;
server 8.8.4.4:53;
}
server {
listen 53 udp;
proxy_pass dns_servers;
proxy_timeout 20s;
}
}
Unix Socket 代理
stream {
server {
listen unix:/tmp/stream.sock;
proxy_pass unix:/tmp/backend.sock;
}
}
3. 负载均衡
配置示例
stream {
upstream mysql_backend {
hash $remote_addr consistent; # 一致性哈希
server mysql1:3306 weight=5;
server mysql2:3306;
server mysql3:3306 backup;
}
server {
listen 3306;
proxy_pass mysql_backend;
}
}
负载均衡算法
| 算法 | 指令 | 说明 |
|---|---|---|
| 轮询 | 默认 | 加权轮询 |
| 最少连接 | least_conn; |
连接数最少优先 |
| 哈希 | hash key [consistent]; |
基于键哈希 |
| 最少时间 | least_time header | last_byte | last_byte inflight; |
最小响应时间(NGINX Plus) |
| 随机 | random [two] [least_conn]; |
随机选择 |
server 参数
| 参数 | 说明 |
|---|---|
weight=N |
权重 |
max_conns=N |
最大连接数 |
max_fails=N |
失败次数阈值 |
fail_timeout=T |
失败统计时间 |
backup |
备份服务器 |
down |
标记不可用 |
resolve |
解析域名 IP 变化 |
新负载均衡算法
least_time(最小响应时间)
版本要求:NGINX Plus
upstream mysql_backend {
least_time header; # 或 last_byte, last_byte inflight
server 192.168.1.1:3306;
server 192.168.1.2:3306;
zone mysql 64k;
}
参数说明:
| 参数 | 说明 |
|---|---|
header |
以接收到上游第一个字节的时间为度量 |
last_byte |
以接收到上游完整响应的时间为度量 |
last_byte inflight |
考虑正在传输的数据 |
random(随机选择)
upstream backend {
random; # 纯随机
# random two; # 随机选两个,按权重选
# random two least_conn; # 随机选两个,选连接少的
server 192.168.1.1:3306;
server 192.168.1.2:3306;
}
参数说明:
| 参数 | 说明 |
|---|---|
two |
随机选择两个上游服务器,再根据负载均衡策略选择 |
least_conn |
与 two 配合,选择连接数较少的 |
upstream zone 共享内存
zone 指令启用 upstream 配置的共享内存,多 worker 进程间共享连接状态:
upstream backend {
zone backend 64k; # 64k 共享内存
server 192.168.1.1:3306;
server 192.168.1.2:3306;
keepalive 32;
}
说明:
- 共享内存使所有 worker 进程共享 upstream 状态
- 必需用于
least_conn、least_time、健康检查等 - 大小根据上游服务器数量调整
4. 核心指令
listen 指令
server {
listen 80; # TCP
listen 53 udp; # UDP
listen 443 ssl; # TLS
listen 12345 udp reuseport; # UDP + reuseport
listen [::]:80; # IPv6
listen unix:/tmp/stream.sock; # Unix Socket
}
参数说明:
| 参数 | 说明 |
|---|---|
ssl |
启用 SSL |
udp |
UDP 协议 |
reuseport |
每个 worker 独立监听 |
proxy_protocol |
启用 PROXY 协议 |
backlog=N |
连接队列长度 |
so_keepalive |
TCP keepalive |
transparent |
启用透明代理 |
proxy_pass 指令
server {
listen 3306;
proxy_pass 192.168.1.1:3306;
proxy_pass backend;
proxy_pass $upstream;
}
超时配置
server {
proxy_timeout 10m; # 客户端/后端之间读写超时(默认 10m)
proxy_connect_timeout 60s; # 连接后端超时(默认 60s)
}
缓冲配置
server {
proxy_buffer_size 16k; # 读写缓冲区大小(默认 16k)
}
其他核心指令
| 指令 | 语法 | 默认值 | 上下文 | 说明 |
|---|---|---|---|---|
proxy_bind |
proxy_bind address [transparent]; |
— | stream, server | 指定代理连接使用的本地地址 |
proxy_half_close |
proxy_half_close on | off; |
off | stream, server | 启用 TCP 半关闭支持 |
proxy_responses |
proxy_responses number; |
— | stream, server (UDP) | UDP 每请求期望响应数 |
proxy_socket_keepalive |
proxy_socket_keepalive on | off; |
off | stream, server | 开启与上游的 TCP keepalive |
示例配置:
# 透明代理
server {
listen 3306 transparent;
proxy_bind $remote_addr transparent;
proxy_pass backend:3306;
}
# UDP 配置
server {
listen 53 udp;
proxy_pass dns_backend:53;
proxy_responses 1; # 每请求期望1个响应
}
# 半关闭支持(TCP 流式场景)
server {
listen 9000;
proxy_half_close on;
proxy_pass backend:9000;
}
5. SSL/TLS 配置
服务端 SSL
stream {
server {
listen 443 ssl;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
proxy_pass backend:8080;
}
}
上游 SSL(连接后端使用 SSL)
server {
listen 3306;
proxy_pass backend:3306;
proxy_ssl on;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /path/to/ca.pem;
proxy_ssl_server_name on;
}
SSL 配置指令
| 指令 | 说明 |
|---|---|
ssl_certificate |
证书文件 |
ssl_certificate_key |
私钥文件 |
ssl_protocols |
启用的协议 |
ssl_ciphers |
加密套件 |
ssl_session_cache |
会话缓存 |
proxy_ssl |
启用上游 SSL |
proxy_ssl_verify |
验证上游证书 |
proxy_ssl_server_name |
启用 SNI |
完整上游 SSL 配置示例
server {
listen 3306;
proxy_pass ssl_backend:3306;
proxy_ssl on;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
proxy_ssl_ciphers HIGH:!aNULL;
proxy_ssl_certificate /path/to/client.crt;
proxy_ssl_certificate_key /path/to/client.key;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /path/to/ca.crt;
proxy_ssl_verify_depth 2;
proxy_ssl_name backend.example.com;
proxy_ssl_session_reuse on;
}
指令说明:
| 指令 | 说明 |
|---|---|
proxy_ssl_certificate |
客户端证书(mTLS) |
proxy_ssl_certificate_key |
客户端证书私钥 |
proxy_ssl_ciphers |
加密套件 |
proxy_ssl_verify_depth |
证书链验证深度 |
proxy_ssl_name |
验证上游证书的域名 |
proxy_ssl_session_reuse |
启用 SSL 会话复用 |
6. 基于名称的虚拟服务器(SNI)
版本要求:1.25.5+
stream {
map $ssl_server_name $backend {
app1.example.com app1_backend;
app2.example.com app2_backend;
default default_backend;
}
upstream app1_backend {
server 192.168.1.1:8080;
}
upstream app2_backend {
server 192.168.1.2:8080;
}
server {
listen 443 ssl;
server_name app1.example.com app2.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
proxy_pass $backend;
}
}
SSL Preread SNI 路由(无需终止 SSL)
版本要求:1.25.5+
使用 ssl_preread 模块在不解密的情况下读取 SNI 信息进行路由:
stream {
ssl_preread on; # 启用 ssl_preread
map $ssl_preread_server_name $backend {
mysql.example.com mysql_backend;
redis.example.com redis_backend;
default default_backend;
}
upstream mysql_backend {
server 192.168.1.1:3306;
}
upstream redis_backend {
server 192.168.1.2:6379;
}
upstream default_backend {
server 192.168.1.3:8080;
}
server {
listen 443;
ssl_preread on; # 在 server 上下文启用
proxy_pass $backend;
}
}
说明:
ssl_preread读取 ClientHello 中的 SNI 扩展- 无需配置 SSL 证书即可实现基于域名的路由
- 适用于多服务共享端口的场景
7. PROXY 协议
接收 PROXY 协议
server {
listen 3306 proxy_protocol;
proxy_pass backend:3306;
}
发送 PROXY 协议
server {
listen 3306;
proxy_protocol on;
proxy_pass backend:3306;
}
PROXY 协议变量
| 变量 | 说明 |
|---|---|
$proxy_protocol_addr |
客户端 IP |
$proxy_protocol_port |
客户端端口 |
$proxy_protocol_server_addr |
服务器 IP |
$proxy_protocol_server_port |
服务器端口 |
8. 速率限制
server {
listen 3306;
proxy_pass backend:3306;
proxy_download_rate 1m; # 限制从后端读取速率(字节/秒)
proxy_upload_rate 1m; # 限制从客户端读取速率(字节/秒)
}
使用变量动态限制:
map $remote_addr $limit_rate {
default 1m;
10.0.0.1 10m; # 特定 IP 更高速率
}
server {
proxy_download_rate $limit_rate;
proxy_upload_rate $limit_rate;
}
9. 故障转移
server {
listen 3306;
proxy_pass backend:3306;
proxy_next_upstream on; # 连接失败时尝试下一台
proxy_next_upstream_timeout 30s; # 总时间限制
proxy_next_upstream_tries 3; # 尝试次数限制
}
10. 连接保持
keepalive 连接池配置
upstream backend {
server 192.168.1.1:3306;
server 192.168.1.2:3306;
keepalive 32; # 空闲连接池大小
keepalive_requests 100; # 单连接最大请求(HTTP 适用)
keepalive_timeout 60s; # 空闲超时
}
指令说明:
| 指令 | 语法 | 默认值 | 说明 |
|---|---|---|---|
keepalive |
keepalive connections; |
— | 保持到上游的空闲连接数 |
keepalive_requests |
keepalive_requests number; |
100 | 单连接最大请求数 |
keepalive_timeout |
keepalive_timeout timeout; |
60s | 空闲连接超时时间 |
11. 内置变量
| 变量 | 说明 |
|---|---|
$remote_addr |
客户端 IP |
$remote_port |
客户端端口 |
$server_addr |
服务器 IP |
$server_port |
服务器端口 |
$protocol |
协议(TCP/UDP) |
$bytes_received |
接收字节数 |
$bytes_sent |
发送字节数 |
$session_time |
会话时间(秒) |
$status |
会话状态 |
$ssl_preread_server_name |
SNI 名称 |
其他 stream 指令
| 指令 | 语法 | 默认值 | 说明 |
|---|---|---|---|
preread_buffer_size |
preread_buffer_size size; |
16k | 预读缓冲区大小 |
preread_timeout |
preread_timeout timeout; |
30s | 预读超时时间 |
resolver |
resolver address ... [valid=time]; |
— | DNS 解析器 |
resolver_timeout |
resolver_timeout time; |
30s | 解析超时 |
tcp_nodelay |
tcp_nodelay on | off; |
on | 启用 TCP_NODELAY |
variables_hash_max_size |
variables_hash_max_size size; |
1024 | 变量哈希表最大大小 |
variables_hash_bucket_size |
variables_hash_bucket_size size; |
64 | 变量哈希表桶大小 |
12. 应用场景示例
MySQL 代理
stream {
upstream mysql_servers {
least_conn;
server mysql1:3306 weight=5;
server mysql2:3306;
server mysql3:3306 backup;
}
server {
listen 3306;
proxy_pass mysql_servers;
proxy_timeout 600s;
proxy_connect_timeout 2s;
}
}
Redis 代理
stream {
upstream redis_servers {
server redis1:6379;
server redis2:6379;
}
server {
listen 6379;
proxy_pass redis_servers;
proxy_timeout 300s;
}
}
DNS 代理
stream {
upstream dns_servers {
server 8.8.8.8:53;
server 8.8.4.4:53;
}
server {
listen 53 udp reuseport;
proxy_pass dns_servers;
proxy_timeout 20s;
proxy_responses 1; # 期望 1 个响应
}
}
日志收集(Syslog)
stream {
upstream syslog_servers {
server syslog1:514;
server syslog2:514;
}
server {
listen 514 udp;
proxy_pass syslog_servers;
proxy_timeout 10s;
}
}
WebSocket 代理(TCP 层)
stream {
upstream websocket_servers {
server ws1:8080;
server ws2:8080;
}
server {
listen 8080;
proxy_pass websocket_servers;
proxy_timeout 3600s; # 长连接超时
}
}
13. 日志配置
stream {
log_format main '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr"';
access_log /var/log/nginx/stream.log main;
server {
listen 3306;
proxy_pass backend:3306;
}
}
14. 健康检查
被动检查(内置)
upstream backend {
server 192.168.1.1:3306 max_fails=3 fail_timeout=30s;
server 192.168.1.2:3306 max_fails=3 fail_timeout=30s;
}
主动检查(NGINX Plus)
upstream backend {
zone backend 64k;
server 192.168.1.1:3306;
server 192.168.1.2:3306;
health_check interval=5s passes=2 fails=3;
health_check_timeout 5s;
}
15. 访问控制模块
ngx_stream_access_module
基于 IP 地址的访问控制,允许或拒绝特定客户端连接。
指令:
| 指令 | 语法 | 默认值 | 上下文 |
|---|---|---|---|
allow |
allow address | CIDR | unix: | all; |
— | stream, server |
deny |
deny address | CIDR | unix: | all; |
— | stream, server |
配置示例:
stream {
# 数据库访问控制
server {
listen 3306;
# 允许内网访问
allow 10.0.0.0/8;
allow 192.168.0.0/16;
allow 172.16.0.0/12;
# 拒绝其他所有
deny all;
proxy_pass mysql_backend;
}
# Redis 访问控制
server {
listen 6379;
# 仅允许特定 IP
allow 192.168.1.100;
allow 192.168.1.101;
deny all;
proxy_pass redis_backend;
}
# 管理端口(仅本地)
server {
listen 9000;
allow 127.0.0.1;
deny all;
proxy_pass admin_backend;
}
}
规则匹配顺序:
- 按配置顺序依次检查
- 首个匹配的规则决定结果
- 未匹配任何规则时默认允许
16. 连接限制模块
ngx_stream_limit_conn_module
限制并发连接数,防止资源耗尽。
指令:
| 指令 | 语法 | 默认值 | 上下文 |
|---|---|---|---|
limit_conn_zone |
limit_conn_zone key zone=name:size; |
— | stream |
limit_conn |
limit_conn zone number; |
— | stream, server |
limit_conn_log_level |
limit_conn_log_level info | notice | warn | error; |
error | stream, server |
配置示例:
stream {
# 按客户端 IP 限制连接数
limit_conn_zone $binary_remote_addr zone=addr:10m;
# 按上游服务器限制连接数
limit_conn_zone $server_addr zone=server:10m;
# MySQL 代理 - 每 IP 最多 10 个连接
server {
listen 3306;
limit_conn addr 10;
proxy_pass mysql_backend;
}
# Redis 代理 - 每 IP 最多 5 个连接
server {
listen 6379;
limit_conn addr 5;
limit_conn_log_level warn;
proxy_pass redis_backend;
}
# 全局连接限制
server {
listen 8080;
limit_conn addr 50; # 每 IP 最多 50
limit_conn server 1000; # 服务总连接上限
proxy_pass backend;
}
}
内存计算:
- 1MB 共享内存可存储约 16,000 个 32 字节 key($binary_remote_addr)
- 或约 8,000 个 IPv6 地址(16 字节)
17. 地理位置模块
ngx_stream_geo_module
根据客户端 IP 地址创建变量值,用于地理路由或访问控制。
指令:
| 指令 | 语法 | 默认值 | 上下文 |
|---|---|---|---|
geo |
geo [$address] $variable { ... } |
— | stream |
配置示例:
stream {
# 基础地理映射
geo $remote_addr $region {
default other;
10.0.0.0/8 internal;
192.168.0.0/16 internal;
172.16.0.0/12 internal;
# 中国大陆 IP 段(示例)
1.0.1.0/24 china;
1.0.2.0/23 china;
# ... 更多 IP 段
}
# 使用变量进行路由
map $region $backend_pool {
internal internal_backend;
china china_backend;
other global_backend;
}
upstream internal_backend {
server 192.168.1.1:3306;
}
upstream china_backend {
server 10.0.1.1:3306;
}
upstream global_backend {
server 10.0.2.1:3306;
}
server {
listen 3306;
proxy_pass $backend_pool;
}
}
高级用法:
stream {
# 使用变量作为地址源
geo $realip_remote_addr $region {
default other;
# ... 配置
}
# 带 CIDR 包含
geo $country {
default XX;
include /etc/nginx/geo/countries.conf;
}
# countries.conf 内容示例:
# 1.0.1.0/24 CN;
# 1.0.2.0/23 CN;
# 1.1.1.0/24 AU;
}
# 使用 GeoIP 数据库(需 ngx_stream_geoip_module)
geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $backend {
default global_backend;
CN china_backend;
US us_backend;
EU eu_backend;
}
}
18. 真实 IP 模块
ngx_stream_realip_module
处理 PROXY 协议头,获取客户端真实 IP 地址。
指令:
| 指令 | 语法 | 默认值 | 上下文 |
|---|---|---|---|
set_real_ip_from |
set_real_ip_from address | CIDR; |
— | stream, server |
real_ip_header |
real_ip_header field; |
proxy_protocol | stream, server |
配置示例:
stream {
server {
listen 3306 proxy_protocol; # 接收 PROXY 协议
# 信任的代理服务器地址
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 172.16.0.0/12;
proxy_pass mysql_backend;
}
}
可用变量:
| 变量 | 说明 |
|---|---|
$realip_remote_addr |
原始客户端地址(PROXY 协议中的地址) |
$realip_remote_port |
原始客户端端口 |
$proxy_protocol_addr |
PROXY 协议中的客户端地址 |
$proxy_protocol_port |
PROXY 协议中的客户端端口 |
$proxy_protocol_server_addr |
PROXY 协议中的目标服务器地址 |
$proxy_protocol_server_port |
PROXY 协议中的目标服务器端口 |
典型场景:
stream {
# 场景:负载均衡器 → NGINX → 后端
server {
listen 3306 proxy_protocol;
# 负载均衡器的 IP
set_real_ip_from 10.0.0.1;
set_real_ip_from 10.0.0.2;
# 使用真实 IP 进行限流
limit_conn_zone $realip_remote_addr zone=conn_limit:10m;
limit_conn conn_limit 10;
# 日志记录真实 IP
log_format main '$realip_remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received';
access_log /var/log/nginx/stream.log main;
proxy_pass mysql_backend;
}
}
19. 高级日志配置
日志格式详解
stream {
# JSON 格式日志
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"server_addr":"$server_addr",'
'"server_port":"$server_port",'
'"protocol":"$protocol",'
'"status":"$status",'
'"bytes_sent":"$bytes_sent",'
'"bytes_received":"$bytes_received",'
'"session_time":"$session_time",'
'"upstream_addr":"$upstream_addr",'
'"upstream_bytes_sent":"$upstream_bytes_sent",'
'"upstream_bytes_received":"$upstream_bytes_received",'
'"upstream_connect_time":"$upstream_connect_time"'
'}';
# 详细格式日志
log_format detailed '$remote_addr - [$time_local] '
'$protocol/$status '
'sent:$bytes_sent recv:$bytes_received '
'time:$session_time '
'upstream:$upstream_addr '
'upstream_time:$upstream_connect_time';
# 条件日志(仅记录错误)
map $status $loggable {
~^[23] 0;
default 1;
}
server {
listen 3306;
access_log /var/log/nginx/stream.json json_combined;
access_log /var/log/nginx/stream_errors.log detailed if=$loggable;
proxy_pass backend;
}
}
日志缓冲与压缩
stream {
server {
listen 3306;
# 缓冲写入(提升性能)
access_log /var/log/nginx/stream.log main buffer=32k flush=5s;
# gzip 压缩日志
access_log /var/log/nginx/stream.log.gz main gzip buffer=32k;
proxy_pass backend;
}
}
open_log_file_cache
缓存日志文件描述符,减少文件打开操作:
stream {
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
server {
listen 3306;
access_log /var/log/nginx/stream.log main;
proxy_pass backend;
}
}
参数说明:
| 参数 | 说明 |
|---|---|
max |
缓存的最大文件描述符数 |
inactive |
非活动文件保留时间 |
valid |
检查文件是否有效的时间间隔 |
min_uses |
最小使用次数才缓存 |
20. Stream 模块源码架构分析
基于 nginx 1.31.0 源码(lib/nginx/src/stream/,24 个 .c 文件)。
20.1 模块文件结构
src/stream/
├── ngx_stream.c # 模块入口(252 行)
├── ngx_stream_core_module.c # 核心配置(1524 行)
├── ngx_stream_handler.c # 连接处理(390 行)
├── ngx_stream_proxy_module.c # 反向代理(2870 行)
├── ngx_stream_upstream.c # upstream 管理
├── ngx_stream_upstream_round_robin.c # 负载均衡
├── ngx_stream_ssl_module.c # SSL/TLS 支持
├── ngx_stream_ssl_preread_module.c # SSL preread(SNI 路由)
├── ngx_stream_access_module.c # IP 访问控制
├── ngx_stream_log_module.c # 访问日志
├── ngx_stream_variables.c # 变量支持
├── ngx_stream_return_module.c # 返回响应
├── ngx_stream_map_module.c # 变量映射
├── ngx_stream_split_clients_module.c # A/B 测试
└── modules/ # 其他子模块
20.2 处理阶段(7 Phase)
// src/stream/ngx_stream_core_module.h
typedef enum {
NGX_STREAM_POST_ACCEPT_PHASE = 0, // 接受后处理(proxy_protocol)
NGX_STREAM_PREACCESS_PHASE, // 预访问检查
NGX_STREAM_ACCESS_PHASE, // 访问控制(allow/deny)
NGX_STREAM_SSL_PHASE, // SSL 握手
NGX_STREAM_PREREAD_PHASE, // 协议识别预读(SNI 检测)
NGX_STREAM_CONTENT_PHASE, // 内容处理(调用 handler)
NGX_STREAM_LOG_PHASE // 日志记录
} ngx_stream_phases;
20.3 TCP 代理处理流程
client 连接
|
v
ngx_stream_init_connection()
|
+-- 创建 ngx_stream_session_t
+-- 执行 phases (accept, access, ssl, preread, content)
|
v
ngx_stream_proxy_handler()
|
+-- ngx_stream_proxy_connect() 连接上游服务器
+-- ngx_stream_proxy_process() 双向数据转发
|
v
双向数据流:
client <---> ngx_stream_proxy_process <---> upstream
20.4 UDP 代理处理流程
client 数据
|
v
ngx_stream_core_udp_handler()
|
+-- 创建临时 UDP session
+-- ngx_stream_proxy_init_upstream() 获取上游地址
+-- sendto() 直接发送数据
|
v
通过 udp_connection_pool 复用连接
20.5 SSL Preread 模块(SNI 路由)
// src/stream/ngx_stream_ssl_preread_module.c
// 在 PREREAD_PHASE 阶段解析 TLS ClientHello
// 提取 SNI(Server Name Indication)用于路由决策
typedef struct {
ngx_uint_t server_name_len;
u_char server_name[256];
} ngx_stream_ssl_preread_ctx_t;
// 根据 $ssl_preread_server_name 变量选择 upstream 组
20.6 关键源码路径
| 功能 | 文件路径 | 行数 |
|---|---|---|
| Stream 入口 | src/stream/ngx_stream.c |
252 |
| 核心配置 | src/stream/ngx_stream_core_module.c |
1524 |
| 连接处理 | src/stream/ngx_stream_handler.c |
390 |
| 反向代理 | src/stream/ngx_stream_proxy_module.c |
2870 |
| SSL 模块 | src/stream/ngx_stream_ssl_module.c |
- |
| SSL Preread | src/stream/ngx_stream_ssl_preread_module.c |
- |
| 变量系统 | src/stream/ngx_stream_variables.c |
- |
| 负载均衡 | src/stream/ngx_stream_upstream_round_robin.c |
- |
21. Mail 模块架构概述
基于 nginx 1.31.0 源码(lib/nginx/src/mail/,14 个 .c 文件)。
21.1 协议支持
| 协议 | 端口 | SSL 端口 |
|---|---|---|
| IMAP | 143 | 993 |
| POP3 | 110 | 995 |
| SMTP | 25/587 | 465 |
21.2 模块文件结构
src/mail/
├── ngx_mail.c # 模块入口(486 行)
├── ngx_mail_core_module.c # 核心配置(534 行)
├── ngx_mail_handler.c # 连接处理(750 行)
├── ngx_mail_imap_module.c # IMAP 模块
├── ngx_mail_imap_handler.c # IMAP 协议处理
├── ngx_mail_pop3_module.c # POP3 模块
├── ngx_mail_pop3_handler.c # POP3 协议处理
├── ngx_mail_smtp_module.c # SMTP 模块
├── ngx_mail_smtp_handler.c # SMTP 协议处理
├── ngx_mail_proxy_module.c # 邮件代理
├── ngx_mail_auth.c # 认证核心
└── ngx_mail_variables.c # 变量支持
21.3 认证机制支持
- PLAIN、LOGIN(基础认证)
- CRAM-MD5(挑战-响应认证)
- EXTERNAL(外部认证)
- APOP(POP3 专用)
21.4 代理流程
client 连接
|
v
ngx_mail_init_connection()
|
+-- 根据端口识别协议(IMAP/POP3/SMTP)
+-- ngx_mail_auth() 执行认证
|
v
ngx_mail_proxy_init() 连接上游邮件服务器
|
v
协议转发: client <-> proxy <-> upstream
源码分析基于 nginx 1.31.0
源码目录:lib/nginx/src/stream/ 和 lib/nginx/src/mail/