Назад | Перейти на главную страницу

Как проксировать несколько TCP-потоков на один порт с помощью nginx

С помощью директивы http nginx вы можете иметь несколько серверов на одном порте с разными именами:

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; }


}

Да, если nginx был скомпилирован с --with-stream. https://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. Итак, у вас должен быть прокси для db1.example.com listenна другом port чем прокси для db2.example.com. В противном случае nginx не знал бы, как маршрутизировать пакеты между двумя восходящими потоками. Приносим извинения за неправильное понимание вашего исходного сообщения. server_name не допускается в определениях потоков, потому что, в отличие от заголовков http, в пакете tcp / udp нет дополнительных метаданных, которые идентифицируют, какой DNS использовался для передачи пакета на nginx.

Можно направлять соединения на основе заголовка SNI, используя Модуль предварительного чтения ssl nginx.

Это зависит от того, как клиент указывает заголовок SNI при открытии соединения.

В приведенном ниже примере nginx прослушивает соединения на порту 443. Соединение с present.myglance.org:443 перенаправляется на порт 4443 (это http-сервер, не показан). Соединение с присутствием-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;
    }
}

Я много раз искал это, к сожалению, это невозможно, поскольку TCP не имеет понятия имен серверов, поэтому это невозможно. Он работает только в HTTP, потому что клиент отправляет имя хоста, к которому он пытается получить доступ, как часть запроса, позволяя NGINX сопоставить его с конкретным блоком сервера.

Очень обидно, так как мне бы очень хотелось направить TCP-трафик на основе url-адреса.