Nginx reescribe en la máquina acoplable cuando el puerto host! = Puerto de contenedor


10

Estoy tratando de ejecutar múltiples contenedores acoplables, todos ejecutando nginx escuchando en el puerto 80, pero con diferentes puertos de host asignados al puerto de contenedores 80.

En su mayor parte, esto funciona, excepto cuando nginx realiza una redirección debido a la falta de una barra diagonal final.

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

Dada la configuración nginx anterior y un contenedor docker ejecutándolo con el puerto host 8080 asignado al puerto 80 del contenedor, puedo obtener 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 ...

pero si solicito localhost: 8080 / docs obtengo una redirección a 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 ...

¿Cómo puedo obtener nginx para preservar el puerto original al hacer la redirección? Intenté mirar port_in_redirect y server_name_in_redirect pero no me ayudaron.


EDITAR

Basado en https://forum.nginx.org/read.php?2,261216,261216#msg-261216, esto no parece posible en este momento.


Mire en el contenedor nginx-proxy , para que no tenga que hacer nada de esta basura de reescritura de puertos locos.
Michael Hampton

Realmente no quiero nada equilibrado delante de estos contenedores. Tengo un archivo docker-compose que establece el puerto externo en función de una env env, y la mayoría de las veces simplemente "docker-compose up -d" este archivo una vez. Sin embargo, por razones de prueba y para permitirme trabajar en otras cosas, quiero poder hacer "PORT = 8080 docker-compose -p test up -d" para girar un conjunto completamente nuevo de contenedores (debido al nuevo nombre del proyecto ) que se asignan a un puerto de host diferente.
Ibasa

Ack, también me encontré con este problema. Supongo que tendré que ir a Vanilla Nginx o mover las cosas en 8080 a otra cosa.
Ken

Respuestas:


2

La solución más simple es eliminar la indexdirectiva y no confiar en $uri/redirecciones explícitas o implícitas . Por ejemplo:

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

Este no es un comportamiento idéntico, ya que evita la redirección por completo. Si desea una redirección de barra diagonal como la que proporciona el módulo de índice, se requiere una solución más compleja. Por ejemplo:

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 dije en la pregunta, he intentado esto, agregué port_in_redirect off; al bloque http, el mismo resultado de una redirección a localhost / docs /, trató de agregar server_name_in_redirect off; también. Todavía redirige a localhost / docs /
Ibasa

@Ibasa Sí, lo siento por eso. Leer dos veces, escribir una vez. Debe tratar de recordar eso.
Richard Smith

5

Los clientes HTTP pondrán el puerto en el encabezado Host. Si utiliza el valor original del encabezado del host al hacer la redirección, debería funcionar como se esperaba. Probé el siguiente código y parece estar haciendo exactamente lo que solicitó:

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 es técnicamente la respuesta correcta. También funciona con IP, por ejemplo, una solicitud a 127.0.0.1:8000 tendrá 127.0.0.1:8000 como http_host. Esto se debe a que, de acuerdo con: tools.ietf.org/html/rfc2616#section-14.23 http_host necesita satisfacer la ambigüedad, a lo que se agregará un puerto. Si se omiten los puertos, los valores predeterminados están implícitos (por ejemplo, 80 o 443). Así que esta solución debería ser la más limpia para trabajar ...
lifeofguenter

0

Solo sigue esta simple solución

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

0

Interesante ... Encontré precisamente este problema y pude solucionarlo mucho como sugiere la respuesta de Richard Smith :

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

¿La única diferencia es que no especifico index.html?

Especifique el código de error para evitar un bucle de redireccionamiento.

Todavía estoy esperando los comentarios del soporte de nginx.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.