如何使用 nginx 代理一个端口上的多个 tcp 流

如何使用 nginx 代理一个端口上的多个 tcp 流

使用 nginx http 指令,您可以在同一个端口上拥有具有不同名称的多个服务器:

server {
    listen       80;
    server_name server1.example.com;
    location / {
      proxy_pass http://server1.example.com;
    }
}
server {
    listen       80;
    server_name server2.example.com;
    location / {
      proxy_pass http://server2.example.com;
    }
}

是否可以让 nginx 代理多个 mysql 服务器在同一端口上使用不同的名称,就像使用 http 一样?它们不是集群的一部分。它们有不同的、不相关的表。

stream {
  upstream db1.example.com {
    server db1.example.com:3306;
    #server_name db1.example.com; "server_name" directive is not allowed here
  }
  upstream db2.example.com {
    server db2.example.com:3306;
  }

  server {
    listen 3306;
    proxy_pass db1.example.com;
  }
  #duplicate "3306" address and port pair
  #server { listen 3306; proxy_pass db2.example.com; }


}

答案1

是的,如果 nginx 是用 编译的--with-streamhttps://www.nginx.com/resources/admin-guide/tcp-load-balancing/


以下是具有相同端口的示例之一:

upstream stream_backend {
    hash $remote_addr;

    server backend1.example.com:12345;
    server backend2.example.com:12345;
    server backend3.example.com:12346;
}

第二次更新:

你显然不能做这样的事情:

stream {
  upstream db1.example.com {    
    server db1.example.com:3306;
    #server_name db1.example.com; "server_name" directive is not allowed here
  }
  upstream db2.example.com {
    server db2.example.com:3306;
  }

  server {
    listen 3306;
    proxy_pass db1.example.com;
  }
  #duplicate "3306" address and port pair
  #server { listen 3306; proxy_pass db2.example.com; }    
}

因为上游的 nginx 代理db1.example.com正在与 争夺db2.example.com端口 3306 上的数据包。因此,您必须在代理之外的listen另一个代理上为 db1.example.com 设置代理。否则,nginx 将不知道如何将数据包路由到两个上游和从这两个上游路由。抱歉误解了您的原始帖子。 在流定义中不允许使用 ,因为与 http 标头不同,tcp/udp 数据包中没有其他元数据来标识使用哪个 DNS 将数据包发送到 nginx。portdb2.example.comserver_name

答案2

可以使用nginx ssl 预读模块。

这取决于客户端在打开连接时指定 SNI 标头。

在下面的示例中,nginx 监听端口 443 上的连接。与 presence.myglance.org:443 的连接被转发到端口 4443(这是 http 服务器,未显示)。与 presence-s.myglance.org:443 的连接被转发到监听端口 5502 的流服务器,该服务器终止 SSL 连接并转发到端口 6502。

stream  {

    ############################################################
    ### logging
    log_format log_stream '$remote_addr [$time_local] $protocol [$ssl_preread_server_name] [$ssl_preread_alpn_protocols] [$internalport] '
        '$status $bytes_sent $bytes_received $session_time';

    error_log   /home/Logs/error.log debug;
    access_log  /home/Logs/access.log log_stream;

    ### https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html

    #########################################################################
    # Connections on 443 could be raw socket or https / wss
    # Distinguish between the two based on the SNI (preread server name)
    # Server names with -s are raw socket connections
    # Server names without -s are https or wss connections
    map $ssl_preread_server_name $internalport {
        presence-s.myglance.org      5502;
        presence.myglance.org        4443;
        default                      glance-no-upstream-instance;
    }

    # Note this does not terminate the ssl connection.  It just reads the SNI
    # header and forwards to the appropriate port
    server {
        listen                  443;
        ssl_preread             on;
        proxy_connect_timeout   20s;  # max time to connect to pserver
        proxy_timeout           30s;  # max time between successive reads or writes
        proxy_pass              127.0.0.1:$internalport;
    }    

    server {
        listen                 5502 ssl;
        ssl_preread            off;
        proxy_pass             127.0.0.1:6502;
    }
}

答案3

我一直在为此努力寻找,但不幸的是,这是不可能的,因为 TCP 没有服务器名称的概念,所以这是不可能的。它只在 HTTP 中有效,因为客户端会将其尝试访问的主机名作为请求的一部分发送,从而允许 NGINX 将其与特定的服务器块匹配。

非常沮丧,因为我真的很想根据 URL 来引导 TCP 流量

相关内容