Nginx Stream 是 Nginx 提供的一项用于处理 TCP 和 UDP 流量的模块,通常用于反向代理、负载均衡等场景。它特别适用于需要处理非 HTTP 流量的协议,比如数据库、DNS、FTP、SMTP、TLS/SSL 等。

一、Nginx Stream 的基本概念

Nginx 通常用于 HTTP 反向代理和负载均衡,但对于非 HTTP 协议(如 TCP 和 UDP 流量),Nginx 提供了 stream 模块。这个模块使 Nginx 可以作为反向代理或负载均衡器来处理 TCP/UDP 请求。

特性:

  • 支持 TCP/UDP 协议
  • 负载均衡
  • 反向代理
  • 基于 IP 地址的会话保持
  • 支持 SSL/TLS
  • 支持访问控制

二、Nginx Stream 配置基础

1. 安装和启用 Stream 模块

确保 Nginx 编译时启用了 --with-stream 选项。可以通过以下命令确认 Nginx 是否支持 stream 模块:

nginx -V 2>&1 | grep -- '--with-stream'

如果输出中有 --with-stream,表示 Nginx 支持该模块。

2. 基本配置结构

Stream 配置和 HTTP 配置类似,但 stream 是与 http 独立的块。通常放在 /etc/nginx/nginx.conf 文件的顶级配置中。

示例:简单的 TCP 代理

stream {
    server {
        listen 3306;
        proxy_pass db_backend;
    }

    upstream db_backend {
        server 192.168.1.100:3306;
        server 192.168.1.101:3306;
    }
}

这个配置将监听本地的 3306 端口,将 MySQL 请求代理到两个后端服务器 192.168.1.100192.168.1.101

3. UDP 代理配置

UDP 和 TCP 配置基本相同,唯一不同的是协议。我们只需要在 listen 中指定 udp

示例:简单的 UDP 代理

stream {
    server {
        listen 53 udp;
        proxy_pass dns_backend;
    }

    upstream dns_backend {
        server 8.8.8.8:53;
        server 8.8.4.4:53;
    }
}

这个配置将 DNS 请求代理到 Google 的公共 DNS 服务器。

4. 访问控制

Nginx Stream 模块支持基于 IP 的访问控制(类似于 HTTP 中的 allowdeny 指令)。

示例:基于 IP 的访问控制

stream {
    server {
        listen 3306;
        proxy_pass db_backend;

        allow 192.168.1.0/24;
        deny all;
    }
}

此配置允许来自 192.168.1.0/24 网段的客户端访问 MySQL,其它所有访问将被拒绝。

5. 日志配置

默认情况下,stream 不像 http 那样有详细的日志配置。可以启用日志功能以跟踪流量。

示例:启用日志

stream {
    log_format main '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';

    access_log /var/log/nginx/stream_access.log main;

    server {
        listen 3306;
        proxy_pass db_backend;
    }
}

该配置启用了自定义日志格式,并将日志记录到 /var/log/nginx/stream_access.log

三、Nginx Stream 高级配置

1. 基于源 IP 的会话保持

Stream 模块支持会话保持,确保来自同一 IP 的请求被路由到相同的后端服务器。

示例:IP 哈希负载均衡

stream {
    upstream db_backend {
        hash $remote_addr consistent;
        server 192.168.1.100:3306;
        server 192.168.1.101:3306;
    }

    server {
        listen 3306;
        proxy_pass db_backend;
    }
}

这个配置使用 IP 地址哈希来实现会话保持,确保来自同一 IP 的请求总是路由到同一个后端服务器。

2. 基于 SSL 的安全代理

Stream 模块支持为 TCP 流量启用 SSL/TLS 加密。通常用于加密数据库连接或邮件服务器之间的通信。

示例:SSL/TLS 加密代理

stream {
    upstream db_backend {
        server 192.168.1.100:3306;
        server 192.168.1.101:3306;
    }

    server {
        listen 3306 ssl;
        proxy_pass db_backend;
        ssl_certificate /etc/nginx/ssl/nginx.crt;
        ssl_certificate_key /etc/nginx/ssl/nginx.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
    }
}

此配置为 3306 端口上的 TCP 连接启用了 SSL 加密,确保客户端和 Nginx 之间的通信是加密的。

3. 基于 SNI 的多服务配置

Nginx Stream 模块也支持 SNI(Server Name Indication)用于基于域名区分 SSL 服务。

示例:基于 SNI 的 SSL 代理

stream {
    server {
        listen 443 ssl;
        ssl_certificate /etc/nginx/ssl/default.crt;
        ssl_certificate_key /etc/nginx/ssl/default.key;

        ssl_preread on;

        # 基于域名路由
        set $target_backend "";

        if ($ssl_preread_server_name = "mysql.example.com") {
            set $target_backend mysql_backend;
        }

        if ($ssl_preread_server_name = "pgsql.example.com") {
            set $target_backend pgsql_backend;
        }

        proxy_pass $target_backend;
    }

    upstream mysql_backend {
        server 192.168.1.100:3306;
    }

    upstream pgsql_backend {
        server 192.168.1.101:5432;
    }
}

在这个配置中,根据 SNI 的值,Nginx 将客户端请求路由到不同的后端服务。

4. 健康检查

Stream 模块也支持主动健康检查,可以定期检查后端服务器是否正常工作。

示例:健康检查配置

stream {
    upstream db_backend {
        server 192.168.1.100:3306;
        server 192.168.1.101:3306;
        health_check interval=10s fails=3 passes=2;
    }

    server {
        listen 3306;
        proxy_pass db_backend;
    }
}

每 10 秒对后端服务器进行一次健康检查,如果某个服务器连续 3 次失败,它将被标记为不可用。

四、Nginx Stream 使用注意事项

  1. 资源消耗:Nginx 处理 TCP/UDP 流量时会比 HTTP 模式消耗更多资源,特别是在启用了 SSL/TLS 的情况下。
  2. SSL 性能:启用 SSL/TLS 代理时,请注意选择合适的加密协议和加密套件,以避免性能下降。
  3. 日志:默认情况下,Nginx Stream 不记录访问日志。如果需要监控 TCP/UDP 流量,需要手动配置日志。
  4. 健康检查:对于高可用性部署,启用健康检查至关重要。
  5. 连接数限制:确保在高负载环境中为 Nginx 配置足够的文件描述符和连接数限制,避免超出系统资源。

五、总结

Nginx Stream 模块提供了灵活的方式来处理 TCP 和 UDP 流量,支持反向代理、负载均衡、SSL/TLS 加密等高级特性。它可以很好地集成到非 HTTP 的应用中,比如数据库代理、邮件代理、DNS 代理等。