【问题标题】:Nginx Reverse Proxy not redirecting?Nginx反向代理不重定向?
【发布时间】:2019-03-12 00:38:04
【问题描述】:

更新

这个问题的细节越来越长,但我认为它可以缩小到这一点:

由于某种原因,当 Nginx 试图确定是否代理请求时,主机名对它很重要。如果主机名设置为git.example.com,请求似乎不会通过,但如果它设置为203.0.113.2,那么它会通过。为什么主机名很重要?

Filed an issue with Nginx here 还有docker compose

原始问题的开始

当我直接在浏览器栏中输入反向代理的 IP 地址时,它会执行重定向。

当使用通过 /etc/hosts 条目 203.0.113.2 git.example.com 解析的 URL 时,将显示“欢迎使用 Ngnix 页面”。有任何想法吗?这是配置:

server {
    listen 203.0.113.2:80 default_server;
    server_name 203.0.113.2 git.example.com;

    proxy_set_header X-Real-IP  $remote_addr; # pass on real client IP

    location / {
        proxy_pass http://203.0.113.1:3000;
    }
}

这是用于启动整个项目的docker-compose.yml 文件:

version: '3'
services:
  gogs-nginx:
    build: ./proxy
    ports:
      - "80:80"
    networks:
      mk1net:
        ipv4_address: 203.0.113.2
  gogs:
    image: gogs/gogs
    ports:
      - "3000:3000"
    volumes: 
      - gogs-data:/data
    networks: 
      mk1net:
        ipv4_address: 203.0.113.3
volumes:
  gogs-data:
    external: true
networks:
  mk1net:
    ipam:
      config:
        - subnet: 203.0.113.0/24

一个有趣的事情是我可以导航到例如:

http://203.0.113.2/issues

上述网址的日志是:

gogs-nginx_1 | 203.0.113.1 - - [07/Oct/2018:11:28:06 +0000] "GET / HTTP/1.1" 200 38825 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, 像 Gecko ) Chrome/69.0.3497.100 Safari/537.36" "-"

如果我随后将 203.0.113.2 更改为 git.example.com(这样 url 最终会变为 git.example.com 我得到 Nginxs“404 not found”页面,并且日志显示:

gogs-nginx_1 | 2018/10/07 11:31:34 [error] 8#8: *10 open() "/usr/share/nginx/html/issues" 失败(2:没有这样的文件或目录),客户端:203.0.113.1 ,服务器:localhost,请求:“GET /issues HTTP/1.1”,主机:“git.example.com”

如果我只使用http://git.example.com 作为 URL,我会得到 NGINX 欢迎页面和以下日志:

gogs-nginx_1 | 203.0.113.1 - - [07/Oct/2018:11:34:39 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, 像 Gecko ) Chrome/69.0.3497.100 Safari/537.36" "-"

看起来Nginx理解请求是针对代理的,因为它记录了代理的IP,但它没有重定向到代理并返回304 ...

使用 Curl 执行请求

将 curl 与以代理为目标的主机名参数一起使用,如下所示:

curl -H 'Host: git.example.com' -si http://203.0.113.2

Nginx 欢迎页面中的结果:

    ole@mki:~/Gogs/.gogs/docker$ curl -H 'Host: git.example.com' -si http://203.0.113.2
    HTTP/1.1 200 OK
    Server: nginx/1.15.1
    Date: Sun, 07 Oct 2018 17:09:11 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 03 Jul 2018 13:27:08 GMT
    Connection: keep-alive
    ETag: "5b3b79ac-264"
    Accept-Ranges: bytes

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>

    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>

    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>

但是如果我将主机名更改为这样的 ip 地址:

将 curl 与以代理为目标的主机名参数一起使用,如下所示:

curl -H 'Host: 203.0.113.2' -si http://203.0.113.2

然后代理就可以正常工作了:

    ole@mki:~/Gogs/.gogs/docker$ curl -H 'Host: 203.0.113.2' -si http://203.0.113.2
    HTTP/1.1 302 Found
    Server: nginx/1.15.1
    Date: Sun, 07 Oct 2018 17:14:46 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 34
    Connection: keep-alive
    Location: /user/login
    Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
    Set-Cookie: i_like_gogits=845bb09d69587b81; Path=/; HttpOnly
    Set-Cookie: _csrf=neGgBfG4LdOcdrdeA0snHjVGz4s6MTUzODkzMjQ4NjE5MzEzNzI3OQ%3D%3D; Path=/; Expires=Mon, 08 Oct 2018 17:14:46 GMT; HttpOnly
    Set-Cookie: redirect_to=%252F; Path=/

    <a href="/user/login">Found</a>.

【问题讨论】:

  • 您能否在不将203.0.113.2 git.example.com 添加到/etc/hosts 的情况下ping 到该网址?
  • 是的,我可以直接ping203.0.113.2,也可以pinggit.example.com,两个地址都提供了答案。
  • 另外,如果我停止服务,git.example.com 或 203.0.113.2` 都不会解决,所以我知道它们是同一个 docker 容器 ...
  • 你是如何部署 nginx 容器的?哪个主机在 /etc/hosts 中有额外的条目?
  • 这一切都在我的笔记本电脑上运行。 docker-compose up 启动反向代理和代理所针对的 gogs 容器。这是用于 Gogs 的本地开发设置。

标签: docker nginx docker-compose nginx-reverse-proxy gogs


【解决方案1】:

很抱歉,我没有意识到您这边发生了什么,因为这些信息有时令人困惑,有时又不完整。但是 Stackoverflow 对什么是好问题提供了很好的解释:How to create a Minimal, Complete, and Verifiable example,所以我只是尝试实现一个您可能要构建的系统的最小示例。

下面我将提供所有文件,并将向您展示测试运行。

文件#1:docker-compose.yml

gogs:
  image: gogs/gogs

web:
  build: .
  ports:
  - 8000:80
  links:
  - gogs

我的计算机上的 Docker 已经过时,我不想打扰 Docker 网络,所以我刚刚使用 Docker links 链接了两个容器。这是最重要的部分,该链接将确保(1)我们的web 容器依赖于gogs; (2) 我们可以从web 内部引用gogs IP,就像gogs 一样。 Docker 会将名称解析为分配给容器的 IP。

因为我想要一个最小的例子,所以我已经跳过了其他无关紧要的内容。例如,volume

文件#2:Dockerfile

较新的 Compose 版本支持在 docker-compose.yml 中指定的 config 选项,但我需要一个自定义的 Dockerfile 来代替。这很简单:

FROM nginx:stable-alpine
COPY gogs.conf /etc/nginx/conf.d

文件#3:gogs.conf

最后我们需要为代理配置 Nginx:

server {
  listen 80 default_server;

  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  location / {
    proxy_pass http://gogs:3000;
  }
}

您可能注意到这里我们只是通过名称gogs 引用另一个容器,我们需要知道它公开的端口号。我们知道:3000。

跑步

$ docker-compose build
$ docker-compose up

它已启动并运行:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
1f74293df630        g_web               "nginx -g 'daemon off"   2 minutes ago       Up 26 seconds       0.0.0.0:8000->80/tcp   g_web_1
dfa2dbaa6074        gogs/gogs           "/app/gogs/docker/sta"   2 minutes ago       Up 26 seconds       22/tcp, 3000/tcp       g_gogs_1

web 容器在端口号 8000 处向世界公开。

测试

按 IP

让我们通过IP请求它:

$ curl -si http://192.168.99.100:8000/
HTTP/1.1 302 Found
Server: nginx/1.14.0
Date: Sun, 07 Oct 2018 15:13:55 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 31
Connection: keep-alive
Location: /install
Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
Set-Cookie: i_like_gogits=50411f542e2ae8f8; Path=/; HttpOnly
Set-Cookie: _csrf=ZJxRPqnqayIbpAYgZ22zrPIOaSo6MTUzODkyNTIzNTQ2NTg5MDE1NA%3D%3D; Path=/; Expires=Mon, 08 Oct 2018 15:13:55 GMT; HttpOnly

<a href="/install">Found</a>.

对应的日志文件:

web_1   | 192.168.99.1 - - [07/Oct/2018:15:14:24 +0000] "GET / HTTP/1.1" 302 31 "-" "curl/7.61.1" "-"
gogs_1  | [Macaron] 2018-10-07 15:14:24: Started GET / for 192.168.99.1
gogs_1  | [Macaron] 2018-10-07 15:14:24: Completed GET / 302 Found in 199.519µs
gogs_1  | 2018/10/07 15:14:24 [TRACE] Session ID: 38d06d393a9e9d21
gogs_1  | 2018/10/07 15:14:24 [TRACE] CSRF Token: Xth986dFWhhj8w8vBdIqRZu4SbI6MTUzODkyNTI2NDYxMDYzNzAyNA==

我可以从日志中看到(1)两个容器都工作并且它们被用来处理请求; (2) 192.168.99.1 是我主机的IP地址,这意味着“gogs”通过X-Forwarded-For成功获得了一个真实的请求IP。

按域名

好的,让我们使用域名请求:

$ curl -H 'Host: g.example.com' -si http://192.168.99.100:8000/

相信我,这已经足够了。 Host 是传递域名的 HTTP 协议头。任何浏览器都会在后台执行相同的操作。

对应的日志文件是--

gogs_1  | [Macaron] 2018-10-07 15:32:49: Started GET / for 192.168.99.1
gogs_1  | [Macaron] 2018-10-07 15:32:49: Completed GET / 302 Found in 618.701µs
gogs_1  | 2018/10/07 15:32:49 [TRACE] Session ID: 81f64d97e9c3dd1e
gogs_1  | 2018/10/07 15:32:49 [TRACE] CSRF Token: X5QyHM4LMIfn8OSJD1gwSSEyXV46MTUzODkyNjM2OTgyODQyMjExMA==
web_1   | 192.168.99.1 - - [07/Oct/2018:15:32:49 +0000] "GET / HTTP/1.1" 302 31 "-" "curl/7.61.1" "-"

没有变化,一切正常。

【讨论】:

  • 谢谢@Alexander - 这给了我一些新的工具来尝试 - 比如 curl ......我有一个类似的设置可以工作。只有当我切换到 docker-compose 时,我才开始打嗝,所以我想知道。它显然与主机名有关。如果我直接 curl 代理,我会收到 gogs 响应,但如果我 curl git.example.com,我会收到 Nginx 欢迎页面响应。我会在问题中发布答案。
  • 如果我像这样使用 curl:curl -H 'Host: 203.0.113.2' -si http://203.0.113.2 docker compose 设置工作,但如果我像这样使用它curl -H 'Host: git.example.com' -si http://203.0.113.2 然后我得到 Nginx 欢迎页面......我不明白为什么...因为git.example.com 在IP 地址旁边被列为server_name ...
  • 由于某种原因,当 Nginx 试图确定是否代理请求时,主机名对 Nginx 很重要。如果主机名设置为 git.example.com 请求似乎没有通过,但如果它设置为 203.0.113.2 则它通过。为什么主机名很重要?
  • 另一个观察结果是,如果我像这样直接卷曲 gogs 主机:curl -si http://203.0.113.1:3000/ 我得到的响应与我这样卷曲它时相同:curl -H 'Host: 203.0.113.2' -si http://203.0.113.2 ... 所以它看起来确实像 Nginx当存在主机名而不是 IP 地址时不执行代理...但是为什么呢?
  • 也在Nginx Docker issue中描述了这一点
猜你喜欢
  • 2019-05-23
  • 2020-05-31
  • 2015-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-06
相关资源
最近更新 更多