当主机端口!=容器端口时,Nginx在Docker计算机上重写


10

我正在尝试运行多个都在端口80上运行nginx侦听的docker容器,但将不同的主机端口映射到容器端口80。

在大多数情况下,这是可行的,但nginx由于缺少尾部斜杠而进行重定向时除外。

server {
    listen 80;
    root /var/www;
    index index.html;
    location /docs {}
}

给定上述nginx配置和一个运行它的docker容器,并将其主机端口8080映射到容器端口80,我可以通过curl ok获得localhost:8080 / docs /:

> GET /docs/ HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
* Server nginx/1.9.5 is not blacklisted
< Server: nginx/1.9.5
< Date: Sat, 28 Nov 2015 17:27:05 GMT
< Content-Type: text/html
< Content-Length: 6431
< Last-Modified: Sat, 28 Nov 2015 17:17:06 GMT
< Connection: keep-alive
< ETag: "5659e192-191f"
< Accept-Ranges: bytes
<
... html page ...

但是,如果我请求localhost:8080 / docs,则会重定向到localhost / docs /

> GET /docs HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
* Server nginx/1.9.5 is not blacklisted
< Server: nginx/1.9.5
< Date: Sat, 28 Nov 2015 17:29:40 GMT
< Content-Type: text/html
< Content-Length: 184
< Location: http://localhost/docs/
< Connection: keep-alive
<
... html redirect page ...

进行重定向时,如何让nginx保留原始端口?我尝试查看port_in_redirect和server_name_in_redirect,但它们没有帮助。


编辑

基于https://forum.nginx.org/read.php?2,261216,261216#msg-261216,目前看来这不可能。


查看nginx-proxy容器,因此您无需执行任何此类疯狂的端口重写垃圾操作。
Michael Hampton

我真的不希望在这些容器前保持平衡。我有一个docker-compose文件,该文件基于env var设置外部端口,大多数时候,我只是一次“ docker-compose up -d”该文件。但是出于测试的原因,并允许我从事其他工作,我希望能够执行“ PORT = 8080 docker-compose -p test up -d”来启动一组全新的容器(由于新的项目名称) )映射到其他主机端口。
伊巴萨2015年

阿克,也碰到了这个问题。我猜我将不得不使用nginx或将8080上的内容移动到其他位置。
肯(Ken)

Answers:


2

最简单的解决方案是删除index指令,而不依赖显式或隐式$uri/重定向。例如:

server {
  listen 80;
  root /var/www;
  location /docs {
    try_files $uri $uri/index.html =404;
  }
}

这是不完全相同的行为,因为它完全避免了重定向。如果您想要像索引模块那样的尾部斜杠重定向,则需要更复杂的解决方案。例如:

server {
  listen 80;
  root /var/www;
  location /docs {
    try_files $uri @redirect;
  }
  location @redirect {
    if ($uri ~* ^(.+)/$) { rewrite ^ $uri/index.html last; }
    if (-d $document_root$uri) { return $scheme://$host:8080$uri/; }
    return 404;
  }
}

正如我在尝试过的问题中所说的那样,我添加了port_in_redirect off; 到http块,重定向到localhost / docs /的结果相同,尝试将server_name_in_redirect关闭;也一样 仍重定向到localhost / docs /
Ibasa

@Ibasa是的,对此感到抱歉。读两次-写一次。必须设法记住这一点。
理查德·史密斯

5

HTTP客户端会将端口放在Host标头中。如果在进行重定向时使用主机标头的原始值,则它应能按预期工作。我测试了以下代码,看起来可以完全按照您的要求进行操作:

location ~ ^.*[^/]$ {
    try_files $uri @rewrite;
}
location @rewrite {
    return 302 $scheme://$http_host$uri/;
}

> GET /bla HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 302 Moved Temporarily
< Server: nginx/1.9.7
< Date: Sun, 29 Nov 2015 06:23:35 GMT
< Content-Type: text/html
< Content-Length: 160
< Connection: keep-alive
< Location: http://localhost:8080/bla/

从技术上讲,这是正确的答案。它也可以与IP一起使用,例如,对127.0.0.1:8000的请求将具有127.0.0.1:8000作为http_host。这是因为根据:tools.ietf.org/html/rfc2616#section-14.23 http_host需要满足模棱两可的要求,端口将添加到其中。如果忽略端口,则默认为默认值(例如80或443)。因此,此解决方案应该是最干净的解决方案……
lifeofguenter

0

只需遵循此简单的解决方法

location /app {
    alias /usr/share/nginx/html/folder;
    if (-d $request_filename) {
        rewrite [^/]$ $scheme://$http_host$uri/ permanent;
    }
}

0

有趣的是……我恰好遇到了这个问题,并且能够像理查德·史密斯的答案所建议的那样解决它:

root /var/www;
location = /docs {
    try_files $uri $uri/ =404;
}

唯一的区别是我没有指定index.html

指定错误代码,以避免重定向循环。

仍在等待nginx支持的反馈。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.