我们公司运行着几台虚拟(Ubuntu)服务器。每台服务器都桥接了网络连接,因此它们从路由器(DHCP 保留)获取自己的 IP 地址。我们需要运行几个拥有自己子域的网站。
我们有我们的顶级域名(比如说 example.com)
然后我们有 sub1.example.com、sub2.example.com 和 sub3.example.com
看起来,最简单的方法是运行反向代理(以便将来我们可以将一些移动到云端并使用负载平衡)。
我已经设置了一个运行 NGINX 的 Ubuntu 20.04 LTS 的新虚拟机,并将其配置为反向代理。
我目前有 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 地址等)
为了完整起见,我使用的示例标题为根据服务器名称选择上游
我的配置(已修改):
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 进入一个我授予自己外部访问权限的服务器,然后从那里通过 ssh 进入一个内部服务器。ssh [email protected]
唯一想到的是,这可能无法与现有的 HTTPS 代理很好地运行,但也许stream
模块也应该能够处理这些(如果可以,我是否可以设置标题?否则后端只能看到来自反向代理的请求)。
我怀疑这是一个简单的问题,我忽略了一些东西,但是在花了 8 个小时阅读和尝试不同的事情之后,我觉得是时候寻求帮助了......
答案1
SSH 客户端不使用 TLS 协议的 SNI 扩展,该扩展是为了支持使用 HTTPS 的共享主机而开发的。您可以尝试按以下方式设置 ssh 客户端:
Host example.com *.example.com
ProxyCommand openssl s_client -quiet -servername %h -connect example.com:2222
但是我不知道它是否可行。你可以阅读更多关于s_client
openssl 命令的信息这里。另请查看这篇文章:使用 TLS/SNI 和 NGINX 代理 SSH。
答案2
显而易见的是,ssh 不是 https,并且它的协议不会发送您可以像使用 https 那样进行匹配的主机名。
我有几个主机也有类似的限制,因为它们是没有全局 IPv4 地址的虚拟机。对于这些主机,我使用 IPv6 通过 ssh 访问它们。如果出于某种原因您还没有部署 IPv6,那么您已经落后了好几年了……