如何配置 NGINX 以将外部请求路由到我的阶段和生产 Docker 主机
我有 2 个 FQDN stage.external.example.net
,external.example.net
它们解析到同一个外部公共 IP 地址,例如140.240.40.111
(在外部 DNS 上配置)
针对此 IP 的 HTTPS 请求(例如 GEThttps://stage.external.example.net) 然后被路由到我的 NGINX 服务器,该服务器有一条腿在非军事区例如,172.20.180.111
另一个是我的内部网络,10.222.20.1/16
其中我有2个docker主机,它们在内部进行如下解析:
stage.internal.example.net
=>10.222.20.14
internal.example.net
=>10.222.20.15
我正在尝试配置我的 NGINX 来路由:
- 外部请求
stage.external.example.net:443
至内部stage.internal.example.net:443
- 外部请求
external.example.net:443
至内部internal.example.net:443
stage.external.example.net:443 -> 140.240.40.111:443 -> 172.20.180.111:443 (NGINX) -> 10.222.20.14:443 (stage.internal.example.net)
external.example.net:443 -> 140.240.40.111:443 -> 172.20.180.111:443 (NGINX) -> 10.222.20.15:443 (internal.example.net)
我可以在 access.log 中看到请求到达了我的 NGINX,但是该请求似乎没有被转发到我的 docker 主机。
以下是我尝试过的配置,欢迎任何指点:
nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
upstream internal_stage {
server 10.222.20.14:443; # docker host stage.internal.example.net
}
upstream internal_production {
server 10.222.20.15:443; # docker host internal.example.net
}
# Forward all requests to stage.external.example.net:443
server {
listen 443;
server_name stage.external.example.net;
location / {
proxy_pass http://internal_stage;
}
}
# Forward all requests to external.example.net:443
server {
listen 443;
server_name external.example.net;
location / {
proxy_pass http://internal_production;
}
}
}
更新:更改error_log
为info
我现在可以观察到我得到了400 Bad Request
Client sent invalid request while reading client request line
答案1
似乎后端也https
应该proxy_pass
是https
这样的:
location /upstream {
proxy_pass https://backend.example.com;
}
请检查确保 http 流量上游
答案2
通过使用stream
块和ssl_preread
nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.service-api.log main;
error_log /var/log/nginx/error.service-api.log info;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
include /etc/nginx/passthrough.conf;
直通配置文件
stream {
log_format basic '$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/access.log basic;
error_log /var/log/nginx/error.log;
upstream internal_stage {
server 10.222.20.14:443 max_fails=5 fail_timeout=300; # docker host stage.internal.domain.net
}
upstream internal_production {
server 10.222.20.15:443 max_fails=5 fail_timeout=300; # docker host stage.internal.domain.net
}
map $ssl_preread_server_name $upstream {
stage.external.polylabs.net internal_stage;
external.polylabs.net internal_production;
}
server {
listen 443;
proxy_pass $upstream;
ssl_preread on;
proxy_next_upstream on;
}
}
答案3
您的问题似乎将端口 443 与 HTTPS 混为一谈。如果您指的是端口 443 上加密的 HTTP,那么它就是 https,但 hostname:443 并未告诉我们有关协议或是否有加密的任何信息。这可能是否决该问题的原因。
当您使用“proxy_pass”时,nginx 会将 HTTP 请求转发到指定的地址 - 但 HTTP 明确支持在同一 IP 地址上多路复用不同的(虚拟)主机名。值得一提的是,TLS 中为主机名多路复用(SNI)实现了另一种补充方法,在这里您提供的配置与我推断的您的目标相冲突;在后端连接到 https。您的配置连接到 http。另一个原因可能是有人对您的问题投了反对票。但是 Nginx 的 proxy_pass 指令将自动处理 SNI 握手的重写,因此这不是您当前困境的原因。
话虽如此,除非您明确告诉 Nginx 不要这样做,否则它将验证后端服务器提供的证书。它是否使用由 nginx 验证的证书?您可以使用 openssl 的 s_client 从 nginx 主机对此进行测试。
该请求似乎没有被转发到我的docker主机。
你是如何得出这个结论的?(忽略这一点的理由可能是对你的问题投反对票的另一个原因)。
可能确实如此 - 但即使请求被转发到预期的 IP 地址/端口,如果后端认为它不是“stage.external.domain.net”的原始服务器,也会导致错误。
到目前为止,最简单的解决方案是告诉后端 Web 服务器它确实是“stage.external.domain.net”。但您也可以重写请求……
server_name external.polylabs.net;
location / {
proxy_set_header Host "internal.polylabs.net";
proxy_ssl_verify off;
proxy_pass https://internal.polylabs.net;
}