Nginx

NGINX 反向代理 SSH 映射問題

  • July 3, 2020

我們公司有幾個虛擬(Ubuntu)伺服器在執行。每個都有其網路連接橋接,因此它從路由器獲取自己的 IP 地址(DHCP 保留)。我們需要執行幾個具有自己子域的網站。

我們有我們的頂級域名(比如說 example.com)

然後我們有 sub1.example.com、sub2.example.com 和 sub3.example.com

最簡單的方法似乎是執行反向代理(以便將來我們可以將一些移動到雲並使用負載平衡)。

我已經使用執行 NGINX 的 Ubuntu 20.04 LTS 設置了一個新 VM,並將其配置為反向代理。

我目前有3種配置:

重定向_https:

server {
   listen 80;
   listen [::]:80;
   
   server_name *.example.com;
   return 301 https://$host$request_uri;
}

ssl 代理:

server {
   listen 443 ssl;
   server_name example.com;
   location / {
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header Host $http_host;
       proxy_set_header X-Forwarded_Proto https;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_redirect off;
       proxy_pass https://10.10.x.y;
       proxy_http_version 1.1;
   }
   
   ssl_certificate        /etc/<path_to_cert>/fullchain.pem;
   ssl_certificate_key    /etc/<path_to_cert>/privkey.pem;
}

ssl 代理子域:

server {
   listen 443 ssl;
   server_name sub1.example.com sub2.example.com sub3.example.com;
   location / {
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header Host $http_host;
       proxy_set_header X-Forwarded_Proto https;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_redirect off;
       proxy_pass https://10.10.x.y;
       proxy_http_version 1.1;
   }
   
   ssl_certificate        /etc/<path_to_cert>/fullchain.pem;
   ssl_certificate_key    /etc/<path_to_cert>/privkey.pem;
}

這一切都很好。

為了能夠在家中編輯我們的站點,我想配置代理以傳遞 SSH 流量,這就是我感到困惑的地方。

我在這裡閱讀了許多文章,在其他網站上,NGINX 文件,我似乎不明白這一點。

我按照文件中的範例進行操作: https ://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html

看起來很簡單。

我的配置幾乎相同(僅更改了與我的公司相關的部分,例如 IP 地址等)

為了完整起見,我使用的範例標題為Selecting an upstream based on server name

我的配置(修改):

map $ssl_preread_server_name $name {
   example.com           backend_main;
   sub1.example.com      backend_1;
   sub2.example.com      backend_2;
   sub3.example.com      backend_3;
   default               backend_proxy;
}

upstream backend_main { server 10.10.x.y:22; }
upstream backend_1 { server 10.10.x.y:22; }
upstream backend_2 { server 10.10.x.y:22; }
upstream backend_3 { server 10.10.x.y:22; }
upstream backend_proxy { server 10.10.x.y:22; }

server {
   listen      2222;
   proxy_pass  $name;
   ssl_preread on;
}

log_format proxy '$remote_addr [$time_local] '
   '$protocol $status $bytes_sent $bytes_received '
   '$session_time "$upstream_addr" '
   '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

access_log /var/log/nginx/proxy-access.log proxy;
error_log /var/log/nginx/proxy-error.log;

上面的程式碼塊位於stream {...}/etc/nginx/nginx.conf之後的html {...}塊內(就在註釋mail {...}塊之前)。

路由器獲取外部埠 22 並將其轉發到反向代理的內部埠 2222。

我面臨的問題是map始終選擇預設選項。如果我刪除/評論預設值,我根本無法連接。如果我更改預設 IP 地址,它會將我連接到該伺服器,但同樣,只有“預設”是什麼。

最終目標是能夠直接通過 ssh 進入其中一個子域(例如ssh user@sub1.example.com)。目前,我必須通過 ssh 連接到我給自己提供外部訪問權限的一台伺服器,然後從那裡 ssh 進入內部伺服器。

唯一想到的是,這可能不適用於現有的 HTTPS 代理,但也許stream模組也應該能夠處理這些(如果可以,我可以設置標頭嗎?否則後端只能看到來自反向代理的請求)。

我懷疑這是一個簡單的問題並且我忽略了一些東西,但是在花了 8 個小時閱讀和嘗試不同的東西之後,我覺得是時候尋求幫助了……

SSH 客戶端不使用 TLS 協議的 SNI 擴展,這些擴展是為支持使用 HTTPS 的共享主機而開發的。您可以嘗試通過以下方式設置您的 ssh 客戶端:

Host example.com *.example.com
   ProxyCommand openssl s_client -quiet -servername %h -connect example.com:2222

但是我不知道它是否會起作用。您可以在此處閱讀有關s_clientopenssl 命令的更多資訊。另請查看這篇文章:使用 TLS/SNI 和 NGINX 的代理 SSH

顯而易見的是,ssh 不是 https,它的協議不會發送一個主機名,您可以使用該主機名進行匹配,就像使用 https 一樣。

我有一些具有類似限制的主機,因為它們是沒有全域 IPv4 地址的虛擬機。對於這些,我通過 ssh 和 IPv6 訪問它們。如果由於某種原因您還沒有部署 IPv6,那麼您現在已經落後了幾年…

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