HTTPS + Nginx 反向代理 + URL 重写

HTTPS + Nginx 反向代理 + URL 重写

我正在尝试将所有 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/Servicehttp://192.168.1.2/服务为了使上述工作正常进行。

我不能https://somesite.com/Service跟...共事http://192.168.1.2/你好

或者我无法将其定向到其他端口,例如https://somesite.com/Servicehttp://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 的请求。

相关内容