我正在尝试将所有 HTTPS 流量导向 Nginx 服务器,它会将所有请求作为 HTTP 请求处理到所有内部服务器。到目前为止,我能够让下面的模板适用于我的大多数服务器。
server {
listen 443 default ssl;
ssl_certificate /etc/letencrypt/live/somesite.com/fullchain.pem;
ssl_certificate_key /etc/letencrypt/live/somesite.com/privkey.pem;
server_name somesite.com;
location ^~ /Service {
proxy_pass http://192.168.1.2;
}
location / {
proxy_pass http://192.168.1.3;
}
}
然而,我总是被限制在必须匹配https://somesite.com/Service和http://192.168.1.2/服务为了使上述工作正常进行。
我不能https://somesite.com/Service跟...共事http://192.168.1.2/你好。
或者我无法将其定向到其他端口,例如https://somesite.com/Service和http://192.168.1.2:3000。
例如,当我将上面的内容更改为以下内容时:
location /Service/ {
proxy_pass http://192.168.1.2:80/;
}
location / {
proxy_pass http://192.168.1.3;
}
使用以下日志设置:
log_format upstreamlog '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request upstream_response_time $upstream_response_time msec $msec request_time $request_time';
access_log /var/log/nginx/access.log upstreamlog;
这是我收到的日志:
[22/Jan/2021:09:56:28 +0000] 172.56.38.95 - - - somesite.com to: 192.168.1.2:80: GET /Service/ HTTP/1.1 upstream_response_time 0.004 msec 1611309388.445 request_time 0.004
[22/Jan/2021:09:56:28 +0000] 172.56.38.95 - - - somesite.com to: 192.168.1.2:80: GET /Service/js/default.cache.a331c8c3.js HTTP/1.1 upstream_response_time 0.000 msec 1611309388.547 request_time 0.002
[22/Jan/2021:09:56:28 +0000] 172.56.38.95 - - - somesite.com to: 192.168.1.2:80: GET /Service/favicon.ico HTTP/1.1 upstream_response_time 0.012 msec 1611309388.757 request_time 0.012
[22/Jan/2021:09:56:28 +0000] 172.56.38.95 - - - somesite.com to: 192.168.1.3:80: GET /api/v1/oauth.json?_=1611309389573 HTTP/1.1 upstream_response_time 0.016 msec 1611309388.771 request_time 0.017
从日志中可以看出,前三次获取是正确的。第四次是错误的。之后没有进一步的请求。经过进一步跟踪后,我意识到 192.168.1.2 已经有一个 Nginx 服务器在运行,并使用 FastCGI 处理 PHP 页面。我不知道这是否有区别。
所以我尝试使用改写结合我上面的内容,但我遇到了页面未找到。我推测它似乎不适用于 HTTPS?因此,这让我问了一个问题:如何将 Nginx 配置为使用 URL 重写和 HTTPS 进行外部反向代理。
答案1
看NGINX 文档,第一个例子正是你正在做的事情,并且解释得很好:
如果您location
使用路径 1 配置一个块并proxy_pass
使用路径 2 配置一个块,则最终整个“路径树”将从路径 1 重新定位到路径 2:
server {
...
server_name example.net;
location /some/path/ {
proxy_pass http://www.example.com/link/;
}
}
如果你访问https://example.net/some/path/blah
它会代理到http://www.example.com/link/blah
。
下一个需要注意的是,源服务器究竟返回了什么。它可能会发出一些 HTML、一些 JS、一些 CSS,它们都可能包含 HTTP(S) 链接;其中一些是相对的,但有些不是。非常重要的考虑因素是proxy_pass
指令不会指示 Nginx 重写代理数据中的任何链接。如果有非相对路径,它们将保持原样,客户端会将它们解释为“超出”代理前缀的指令。
正如我们在日志文件中看到的,Web 服务器在请求 2 时返回了一些 Javascript 代码:
[22/Jan/2021:09:56:28 +0000] 172.56.38.95 - - - somesite.com to: 192.168.1.2:80: GET /Service/js/default.cache.a331c8c3.js HTTP/1.1 upstream_response_time 0.000 msec 1611309388.547 request_time 0.002
该代码可能包含一些非相对路径,即它有一个以 开头的路径/api/
。然后,客户端根据该路径发出请求,该路径位于代理树之外(目前仅如此/Service/
),我们在第 4 行看到它:
[22/Jan/2021:09:56:28 +0000] 172.56.38.95 - - - somesite.com to: 192.168.1.3:80: GET /api/v1/oauth.json?_=1611309389573 HTTP/1.1 upstream_response_time 0.016 msec 1611309388.771 request_time 0.017
Nginx 根据其配置,正确地将该请求代理到其他地方(被location /
规则捕获)。
有有多种方式来解决这个问题。如果你只有几个前缀用于非相对路径,并且没有其他东西在使用它们,那么你可以在返回它们时代理它们:
# (inside a "server" block, above "location /" rule)
location /api/ {
proxy_pass http://www.example.com/api/;
}
另一种方法是使用在 Nginx 中安装过滤器ngx_http_sub_module
,它会改变所提供内容,将所有 URI 更新至新的基础。
请记住,没有绝对万无一失的方法可以做到这一点。链接不仅可能出现在基于文本的 HTML、CSS 和 JS 文件中,也可能出现在专有二进制文件中。而且我们事先不知道它们可能包含哪些链接,无法预防性地代理它们。不久前,Adobe Flash 就是这种二进制格式的一个例子。没有人知道将来会发明什么来暴露同样的问题。
答案2
您正在尝试使用代理和重写。但它们需要在不同的位置完成。代理将把收到的相同路径传递到原始服务器。如果您想要重写到另一个位置,您可以在原始服务器上执行此操作,这样它就知道将对 /service 的请求重写为 /hello。否则您将得到 404,因为原始服务器不知道如何处理对 /service 的请求。