【问题标题】:How to configure nginx X-Forwarded-Port to be the originally request port如何将 nginx X-Forwarded-Port 配置为原始请求端口
【发布时间】:2020-06-22 06:54:44
【问题描述】:

我在标准反向代理场景中使用 nginx,将所有对 /auth 的请求传递给另一台主机,但是我正在尝试使用非标准端口。

我的最终目标是将X-Forwarded-Port 标头设置为请求进入的端口。

这是我在 nginx.conf 中的位置块:

location /auth/ {
    proxy_pass       http://otherhost:8090;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port <VAR>;
}

这个 nginx 运行在一个 docker 容器中,该容器被配置为将请求从 8085 转发到容器中的 80,这样 nginx 进程就在监听 80:

0.0.0.0:8085->80/tcp

当我点击网址时:

http://localhost:8085/auth/

我已正确重定向到 http://otherhost:8090,但 X-Forwarded-Port 标头丢失或错误。

我在原始块中有&lt;VAR&gt;,我尝试了以下方法:

  • $server_port - 这是 nginx 正在监听的端口 (80),而不是 请求端口。

  • $pass_port - 在我的设置中似乎为空,所以 nginx 删除了 标题。

  • $http_port - 这是每个请求的随机端口。

  • $remote_port - 这是每个请求的随机端口。

可以在部署时更改我的配置以硬编码到传入请求的已知端口,但理想情况下,我可以更改前端端口而不对 nginx 配置进行任何更改。

我搜索了the nginx variable list,但找不到像$request_port 这样的东西。有什么方法可以实现我的意图吗?

【问题讨论】:

  • 你试过$remote_port吗?除此之外,我很难理解 nginx 正在侦听的端口 ($server_port) 与请求的端口有何不同。
  • @Mehdi - $remote_port 似乎也是每个请求随机的。请求到达 docker 主机的 8085 端口,然后转发到 80 端口的容器,所以 nginx 监听 80 但 URL 中的端口是 8085。

标签: docker nginx reverse-proxy nginx-reverse-proxy x-forwarded-for


【解决方案1】:

我发现的唯一解决方法是使用map 规则从http_host 变量中获取端口,例如

    map $http_host $port {
      default 80;
      "~^[^\:]+:(?<p>\d+)$" $p;
    }

【讨论】:

    【解决方案2】:

    这是编写 Nginx conf 的一个粗略想法,但我相信这可以帮助您进行重定向

    server {    
        listen 80;  
        server_name host.docker.internal;   
    
        # By default land on localhost:80 to root so in root we copied UI build to the ngnix html dir.
        # have a look to docker-compose uiapp service.
        location / {    
                root   /usr/share/nginx/html;   
                index  index.html index.htm;    
        }   
    
       # after location add filter, from which every endpoint starts with or comes in endpoint 
       # so that ngnix can capture the URL and reroute it.
       # like /backend/getUserInfo/<UserId> 
       # In above example /backend is that filter which will be captured by Ngnix and reroute the flow.
        location /backend { 
            proxy_set_header X-Forwarded-Host $host;    
            proxy_set_header X-Forwarded-Server $host;  
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            #proxy_pass http://<ContainerName>:<PortNumber>; 
            # In our case Container name is as we setup in docker-compose `beservice` and port 8080
            proxy_pass http://beservice:8080;   
        }   
    }
    

    更多细节你可以看看这个项目

    https://github.com/dupinder/NgnixDockerizedDevEnv

    【讨论】:

      【解决方案3】:

      在容器内部,您无法访问外部配置。并且 nginx 不支持在大多数配置块中使用环境变量。

      但是,如果您使用poco,您可以在一个简单的 env 文件中定义您的端口、路径等。 docker-compose 配置或环境变量也使用这些定义。例如

      你的配置.env

      PROJECT_HOME=..
      MAGIC_DOCKER_PORT=8085
      

      poco.yml 文件(项目的主要配置,定义计划)

      version: '3.0'
      maintainer: "youremail@yourdomain.com"
      
      environment:
        include: docker/conf/yourconfig.env
      
      plan:
        live:
          description: "your plan to run live"
          docker-compose-file:
            - docker/dc-proxy.yml
            - docker/dc-other-service.yml
      # you can define other plans to run local/dev env
      

      并在 docker/dc-proxy.yml 撰写文件(相关部分):

      version: '3'
      services:
        proxy:
          image: nginx:alpine
          env_file: conf/yourconfig.env
          ports:
            - ${MAGIC_DOCKER_PORT}:80
          command: /bin/sh -c "envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" 
      

      最后你的配置模板相关部分来自 /etc/nginx/conf.d/mysite.template

      listen ${MAGIC_DOCKER_PORT};
      ...
        location /auth/ {
          ...
          proxy_set_header X-Forwarded-Port ${MAGIC_DOCKER_PORT};
          ...
        }
      

      我使用以下文件夹结构来组织文件。这不是强制性的,但对我来说很容易使用,因为我的每个项目结构都是相同的。

      /
        docker                <- all of docker related files here
          conf                <- env files, service configs, etc
          scripts             <- shell scripts which used by containers
          dc-*.yml            <- separate all services into single compose files
        poco.yml              <- main config, "start here" point
        project-related-files <- separated by each service
      

      说明

      在 .env 文件中定义一个键值对。 poco 使用它来创建 docker-compose 文件,它用于在 nginx 容器中创建环境变量。之后使用envsubst填写nginx配置模板,最后启动nginx服务

      【讨论】:

        【解决方案4】:

        我用过这个:

        map $http_x_forwarded_port $my_forwarded_port {
            default $remote_port;
            "~^(.*)$" $1;
        }
        

        所有标头都设置在 nginx 中的变量中,以 http 为前缀。即,如果标题中有 origin = domain.com,则可以使用 $http_origin 获取“domain.com”。所以我的代码将 $my_forwarded_port 设置为转发端口(如果已设置),否则设置为 $remote_port

        【讨论】:

          【解决方案5】:

          奇怪这个还没回答,但是答案是

          proxy_set_header X-Forwarded-Port $server_port;
          

          【讨论】:

          • 感谢您的回答,但我认为情况并非如此。 $server_port 是 nginx 进程正在监听的端口,不一定是发出请求的端口
          • server_port 的文档似乎表明它是发出请求的端口。 nginx.org/en/docs/http/ngx_http_core_module.html$server_port 接受请求的服务器端口
          • 如果nginx前面有一个负载均衡器,它从8000端口获取客户端的请求,重定向到8100,nginx监听8100,那么$server_port就是8100。但是作者需要原始请求中的端口(8000)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-09
          • 2017-01-28
          • 1970-01-01
          • 2015-03-16
          • 2019-11-06
          相关资源
          最近更新 更多