Aristotle
发布于 2024-03-12 / 8 阅读 / 0 评论 / 0 点赞

nginx stream分流,以及proxy_protocol

nginx stream分流,以及proxy_protocol

参考:https://code.evink.cn/2022/06/post/nginx-stream-module/

使用nginx的sni 对stream分流($ssl_preread_server_name)

为什么在stream中使用$ssl_preread_server_name,而在http中使用server_name

在 nginx 的 http 模块中,server_name 指令会首先判断请求是否是 SSL 请求。如果是 SSL 请求,nginx 将会读取 SNI(Server Name Indication)字段来获取请求的主机名。这是因为在 SSL/TLS 握手阶段,客户端会在 ClientHello 消息中包含 SNI 字段,用于指定请求的主机名。

如果不是 SSL 请求,nginx 就会读取 HTTP 请求头部中的 Host 字段来获取请求的主机名。这个 Host 字段包含了 HTTP 请求中的主机名信息,因此可以用来确定应该使用哪个 server 块来处理请求。

而在 stream 模块中,ssl_preread 指令专门用于解析 SNI 字段,因为 stream 模块处理的是 TCP 或 UDP 层面的流量,并不直接处理 HTTP 请求。因此,ssl_preread 指令只能在 TLS 握手阶段获取到 SNI 字段,而无法像 http 模块那样直接获取 HTTP 请求头部的 Host 字段

stream {
   log_format stream_combined '$remote_addr [$time_local] $proxy_protocol_addr -> $upstream_addr [$protocol] $status $bytes_sent $bytes_received';
   access_log /var/log/nginx/stream_access.log stream_combined;

   #sni match
   map $ssl_preread_server_name $backend_name {
    tro.yourdomai tro;
    # 域名都不匹配情况下的默认值
    default web;
    }

    upstream tro {
        server 127.0.0.1:7776;
    }
    #分流到web,这个可以是http模块的监听端口。
    upstream web {
        server 127.0.0.1:8443;
    }

    server {
        listen 443 reuseport;
        listen [::]:443 reuseport;
        proxy_pass  $backend_name;
        ssl_preread on;
	#proxy_protocol on; # 开启Proxy protocol,要求上游服务下支持proxy_protocal,不支持的话对于有些协议这个开启会产生影响导致处理出错。
    }

}

关于proxy_protocal

proxy_protocol 是一种在 TCP 层上的协议,允许代理服务器向上游服务器传递客户端的真实 IP 地址和端口号等信息。

下面是再次解释 proxy_protocol 头部的示例:

phpCopy codePROXY <protocol> <client-ip> <proxy-ip> <client-port> <proxy-port>\r\n
  • PROXY:指示这是 PROXY 协议。

  • <protocol>:指示使用的协议类型,例如 TCP4TCP6

  • <client-ip>:客户端的真实 IP 地址。

  • <proxy-ip>:代理服务器的 IP 地址。

  • <client-port>:客户端的端口号。

  • <proxy-port>:代理服务器的端口号。

所以,示例 PROXY TCP4 192.168.1.1 192.168.1.11 56324 443\r\n 的含义如下:

  • PROXY:这是 PROXY 协议。

  • TCP4:使用的是 IPv4 地址。

  • 192.168.1.1:客户端的真实 IP 地址。

  • 192.168.1.11:代理服务器的 IP 地址。

  • 56324:客户端的端口号。

  • 443:代理服务器的端口号。

这个示例表示客户端 IP 地址为 192.168.1.1,端口号为 56324,连接到代理服务器 192.168.1.11443 端口。

当 Nginx 收到包含这样 PROXY 协议头部的连接时,它会根据这个头部信息将请求转发给上游服务器,并传递客户端的真实 IP 地址。