【问题标题】:Using Nginx to redirect to dynamic host使用 Nginx 重定向到动态主机
【发布时间】:2020-02-24 05:34:57
【问题描述】:

我成功地使用了 Nginx 作为负载均衡器和反向代理,但是这个看起来很简单的问题却让我大吃一惊。我花了几个小时尝试配置 Nginx 但失败了。

我有一组动态的服务器/主机名(因为使用了 docker),比如 service2、service3、service5。我只是想将 nginx 配置为基于 URL 代理到这些。这样做的目的是让我可以从单个端点访问服务,而不是全部公开。

这是我正在尝试使用的代理类型

如果我指定所有端点,它仍然有效,尽管仍然只适用于初始页面,所以 http://localhost:8009/service2 代理到 http://service2/ 但是 http://localhost:8009/service2/home 只是失败,但这是因为它无法匹配位置。如果我只是做定位/它可以工作,那么我只能将所有请求反向代理到单个服务器。

server {
listen       80;
server_name  localhost;

    location /service2 {
        proxy_pass http://service2/;
    }

    location /service5 {
        proxy_pass http://service5/;
    }
}

这可能是我将 url 正则表达式变为动态的最佳示例,但这只是错误,因此假设它对 nginx 无效。

server {
listen       80;
server_name  localhost;

    location ~ (?<myhost>.*)/(?<myuri>.*)$ {
        proxy_pass http://$myhost/$myuri;
    }
}

【问题讨论】:

  • @CalumHalpin Nginx 支持命名捕获就好了。
  • 我不确定 Nginx 如何解析 service2service5 名称。如果它需要使用 DNS,您可能需要在使用带有变量的 proxy_pass 时定义一个 resolver directive。您捕获的内容不包括查询字符串(因为它们不存在于 location 正则表达式中),但您可以使用 proxy_pass http:/$request_uri; 代替,因为该变量已经包含字符串 /serviceX/...
  • @RichardSmith 我已经添加了解决方法,请参见下面的答案,但仍然存在问题。它确实稍微改变了行为,所以它检测到了一些东西,但仍然不太正确。

标签: docker nginx nginx-location nginx-reverse-proxy nginx-config


【解决方案1】:

您使用的正则表达式不正确。您可以通过以下方式实现您想要做的事情

 location ~ /(?<myhost>[^/]+)(/(?<myuri>.*))? {
      return 301 http://$myhost:80/$myuri?$query_string;
    }
➜  ~   curl --head http://127.0.0.1:32769/service1
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.8
Date: Sun, 23 Feb 2020 20:06:29 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: http://service1:80/?

➜  ~   curl --head http://127.0.0.1:32769/service1/test
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.8
Date: Sun, 23 Feb 2020 20:08:43 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: http://service1:80/test?

➜  ~   curl --head http://127.0.0.1:32769/service1/test?x=100
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.8
Date: Sun, 23 Feb 2020 20:08:53 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: http://service1:80/test?x=100

对于proxy_pass,你不需要包含URI或查询字符串,你可以这样做

server {
    listen       80  default_server;
    server_name  _;

    location ~ /(?<myhost>[^/]+) {
        resolver 127.0.0.11 ipv6=off;

        set $target http://$myhost:80;

        proxy_set_header Host $myhost;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass $target;
    }
}

【讨论】:

  • 您好,感谢您的回答。第一个执行“返回 301”的执行重定向。所以它从localhost:8009 重定向到service5 这失败了,因为 service5 没有暴露,所以它需要是一个代理。所以我尝试了你的第二个答案,错误日志显示如下。
  • 2020/02/23 17:45:19 [错误] 6#6: *2 没有定义解析器来解析 service38,客户端:172.28.0.1,服务器:localhost,请求:“GET /service38 HTTP/1.1",主机:"localhost:8009" 172.28.0.1 - - [23/Feb/2020:17:45:19 +0000] "GET /service38 HTTP/1.1" 502 494 "-" "Mozilla/5.0 ( Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" "-"
  • 这是为了调用localhost:8009/service38,我希望代理在幕后从service38 获取数据。我可以使用 nginx 容器中的 curl 调用 service38,但是我的机器上不能直接使用 service38,因此需要代理。
  • 代理通行证只有在 Nginx 可以解析并且可以到达 'service38' 的情况下才会起作用。您在 docker 中托管这些服务吗?这些是服务名称吗?
  • 正确,它们都托管在 docker 和同一网络上。这些是我测试这种方法时的服务名称。目前它们都只是空白的 .net 核心网站。所以 nginx 将 80 端口暴露为 localhost:8009,service38、service39 运行在 80 端口上,但没有暴露在 localhost 上。所以访问它们的唯一方法是通过 nginx 容器。我正在运行“curl service38”,它会从该容器输出响应,以便 nginx 可以看到它。
猜你喜欢
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 1970-01-01
  • 2019-01-28
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
相关资源
最近更新 更多