Nginx

具有多個埠到同一伺服器的 Nginx 反向流代理

  • February 26, 2022

我正在嘗試使用 nginx 作為兩個不同伺服器的反向代理。伺服器需要使用客戶端證書進行身份驗證,這意味著 nginx 被配置為流代理,利用map $ssl_preread_server_nameSNI 檢查發送到正確的伺服器。

這對於它現在託管的這對伺服器非常有用。兩者都在 443 上偵聽,但提供完全不同的服務,但通過 SNI 的重定向效果很好。

問題是其中一台伺服器還使用埠 9997 進行通信 (TLS),我們需要將更多這些埠添加到組合中。目前,我們只是將 nginx 中的流量硬編碼到使用 9997 的一台伺服器上。隨著我們繼續前進並在 9997 上託管內容的其他伺服器,這將不起作用

如何配置 nginx 以將 443 和 9997 流式傳輸到需要這些通信的盒子,同時在需要時繼續將 443 發送到其他伺服器?

它需要是動態的,以便將流量發送到 RIGHT 伺服器。

這是現在有效的配置(一些資訊已編輯):

#user  nobody;
worker_processes  1;

error_log   /var/log/nginx/error.log;
#pid        logs/nginx.pid;


events {
   worker_connections  1024;
}

stream {

   map $ssl_preread_server_name $upstream {
       server1.domain.com server1;
       server2.domain.com server2;
   }

   server {
       listen 443;
       proxy_pass $upstream;

       ssl_preread on;
   }

   server {
       listen 9997;
       proxy_pass 1.2.3.4:9997;
   }


   upstream server1 {
       server 1.2.3.4:443;
   }

   upstream server2 {
       server 1.2.3.5:443;
   }

}

下面的配置應該適合你

stream {

   map $ssl_preread_server_name:$server_port $upstream {
     server1.domain.com:443 server1;
     server2.domain.com:443 server2;
     server1.domain.com:9997 server3;
   }

   server {
     listen 443;
     proxy_pass $upstream;

     ssl_preread on;
   }

   server {
     listen 9997;
     proxy_pass $upstream;
     ssl_preread on;
   }


   upstream server1 {
     server 1.2.3.4:443;
   }

   upstream server2 {
     server 1.2.3.5:443;
   }
   upstream server3 {
     server 1.2.3.4:9997;
   }
}

這是使用 nginx 作為沒有upstream定義的路由器的可能解決方案。upstream當伺服器定義包含命名主機時可能是不可取的,因為如果無法解析命名主機(這可能是 docker 網路的情況),nginx 將無法啟動。以下配置假定僅路由 HTTPS 流量並將所有 HTTP 流量重定向到 HTTPS。

此配置專為在 docker 實例中執行並與其他 docker 服務共享網路的 nginx 設計。dockerservice1並且dockerservice2預計將在埠 443 上偵聽。該resolver 127.0.0.11 ipv6=off valid=1s;行啟用 docker 的本地 DNS 解析器 ( ) 解析主機名,127.0.0.11以便可以從 docker 內部網路解析為 ips。使用此配置,無論引用的 docker servces/hosts 的狀態如何,nginx 都將始終啟動。dockerservice1``dockerservice2

日誌記錄的配置可以省略,但對於診斷目的很有用。

# /etc/nginx/nginx.conf from the nginx docker instance

user nginx;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

events {
       worker_connections 1024;
}

http {
       server {
               listen 80 default_server;
               server_name _;
               return 301 https://$host$request_uri;
       }

       log_format basic
               '$time_local router:RD $status $request_time client: $remote_addr '
               'http://$host$request_uri -> https://$host$request_uri';

       access_log /var/log/nginx/access.log basic;
       error_log /var/log/nginx/error.log;
}

stream {
       map $ssl_preread_server_name:$server_port $upstream {

               hostnames;

               mydomain.com:443 dockerservice1;
               www.mydomain.com:443 dockerservice1;
               test.mydomain.com:443 dockerservice2;
               
               default dockerservice1;
       }

       server {
               listen 443;
               resolver 127.0.0.11 ipv6=off valid=1s;
               proxy_pass $upstream:443;
               ssl_preread on;
       }
       log_format basic
               '$time_local router:RT $status $session_time client: $remote_addr '
               '$ssl_preread_server_name:$server_port -> $upstream ($upstream_addr) '
               'bytes from/to client $protocol $bytes_sent $bytes_received '
               'bytes from/to upstream $upstream_bytes_sent/$upstream_bytes_received '
               'upstream time: $upstream_connect_time';

       access_log /var/log/nginx/access.log basic;
       error_log /var/log/nginx/error.log;
}

注意:如果在不同的 docker 項目/docker-compose.yml 文件(並且可能在同一網路上)上存在 docker 服務和具有相同名稱的 docker 主機名Docker version 20.10.12, build e91ed57,則 DNS 解析器似乎無法可靠地工作,例如127.0.0.11

# project1/docker-compose.yml
version: "3"
services:
 sharedName:
   container_name: sharedName
   hostname: sharedName
   networks:
     - default
     - external
   ...

networks:
 external:
   name: someNetwork
# project2/docker-compose.yml
version: "3"
services:
 sharedName:
   container_name: OTHERContainerName
   hostname: OTHERContainerName
   networks:
     - default
     - external
   ...

networks:
 external:
   name: someNetwork

在上述情況下,預期的行為是主機名 sharedName始終解析為從project1/docker-compose.yml. 觀察到的行為是sharedName隨機解析為容器sharedNameOTHERContainerName. 這也適用於大量項目/容器。

一種可能的解決方案似乎是強制執行在服務名稱之間沒有重複的唯一主機名。

引用自:https://serverfault.com/questions/850714