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.


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;
  }
}

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/

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;
    }
}

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.