Nginx reescreve na máquina docker quando a porta do host! = Porta do contêiner

10

Estou tentando executar vários contêineres do docker, todos executando o nginx escutando na porta 80, mas com diferentes portas de host mapeadas para a porta 80 dos contêineres.

Na maioria das vezes, isso funciona, exceto quando o nginx faz um redirecionamento devido à falta de uma barra final.

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

Dada a configuração do nginx acima e um contêiner do docker executando-o com a porta 8080 do host mapeada para a porta 80 do contêiner, posso obter localhost: 8080 / docs / via curl ok:

> 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 ...

mas se eu solicitar localhost: 8080 / docs, recebo um redirecionamento para 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 ...

Como posso obter o nginx para preservar a porta original ao fazer o redirecionamento? Eu tentei olhar para port_in_redirect e server_name_in_redirect, mas eles não ajudaram.


EDITAR

Com base em https://forum.nginx.org/read.php?2,261216,261216#msg-261216, isso não parece possível no momento.

Ibasa
fonte
Olhe para o contêiner nginx-proxy , para que você não precise fazer nada desse lixo insano de reescrita de porta.
Michael Hampton
Eu realmente não quero nada equilibrando na frente desses contêineres. Eu tenho um arquivo docker-compose que define a porta externa com base em um env var, e na maioria das vezes eu apenas "docker-componho up -d" esse arquivo uma vez. No entanto, por razões de teste e para permitir que eu trabalhe em outras coisas, eu quero poder fazer "PORT = 8080 docker-compose -p test up -d" para ativar um novo conjunto de contêineres (devido ao novo nome do projeto ) mapeados para uma porta de host diferente.
Ibasa
Ack, acabei de encontrar esse problema também. Acho que vou ter que usar o vanilla nginx ou mover o material no 8080 para outra coisa.
Ken

Respostas:

2

A solução mais simples é remover a indexdiretiva e não confiar em $uri/redirecionamentos explícitos ou implícitos . Por exemplo:

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

Esse comportamento não é idêntico, pois evita completamente o redirecionamento. Se você deseja um redirecionamento de barra final, como o módulo de índice fornece, é necessária uma solução mais complexa. Por exemplo:

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;
  }
}
Richard Smith
fonte
Como eu disse na pergunta que tentei, adicionei port_in_redirect off; para o bloco http, mesmo resultado de um redirecionamento para localhost / docs /, tente adicionar off server_name_in_redirect; também. Ainda redireciona para localhost / docs /
Ibasa
@Ibasa Sim, desculpe por isso. Leia duas vezes - escreva uma vez. Deve tentar se lembrar disso.
Richard Smith
5

Os clientes HTTP colocarão a porta no cabeçalho do host. Se você usar o valor original do cabeçalho do host ao fazer o redirecionamento, ele deverá funcionar conforme o esperado. Testei o código a seguir e parece estar fazendo exatamente o que você solicitou:

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/
Florin Asăvoaie
fonte
Esta é tecnicamente a resposta correta. Também funciona com IPs, por exemplo, uma solicitação para 127.0.0.1:8000 terá 127.0.0.1:8000 como http_host. Isso porque de acordo com: tools.ietf.org/html/rfc2616#section-14.23 HTTP_HOST precisa para atender a ambiguousity, para que uma porta irá adicionar. Se as portas forem deixadas de fora, os padrões serão implícitos (por exemplo, 80 ou 443). Portanto, esta solução deve ser o mais limpo para trabalhar com ...
lifeofguenter
0

Basta seguir esta correção simples

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

Interessante ... Encontrei exatamente esse problema e pude corrigi-lo da mesma forma que a resposta de Richard Smith sugere:

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

A única diferença é que eu não especifico index.html?

Especifique o código de erro para evitar um loop de redirecionamento.

Ainda estou aguardando feedback do suporte do nginx.

Kevin W Matthews
fonte