nginx try_files redirige usando un esquema incorrecto cuando está detrás del equilibrador de carga de terminación SSL (haproxy)


8

Tengo un servidor nginx 1.6.2 que se ejecuta como back-end detrás de un equilibrador de carga que finaliza SSL. Toda la comunicación con los servidores de fondo se realiza a través de HTTP.

Diagrama de lo que está sucediendo:

          /--http---> frontend:80  --\
client --+                            +--http---> backend:8000
          \--https--> frontend:443 --/

                      LOAD BALANCER                BACKENDS

Para fines de prueba, solo tengo un back-end en este momento. El equilibrador de carga ejecuta HAProxy 1.5, sobre el que tengo cierto control.

Tengo una try_filesdirectiva bastante típica en mi serverbloque en la configuración de back-end nginx:

server {
    server_name frontend;
    ...
    try_files $uri $uri/ =404;
    ...
}

Ahora, por defecto, cuando accedo a un directorio sin una barra inclinada final, por ejemplo https://frontend/somedir, nginx quiere enviar una redirección HTTP 301 a una URL absoluta como http://frontend:8000/somedir/.

Puedo hacer que nginx omita el número de puerto 8000 usando port_in_redirect off.

Sin embargo, parece que no puedo corregir el http://esquema al comienzo de la redirección que genera nginx. ¡Lo mejor que puedo hacer con nginx es redirigir de https://frontend/somedira http://frontend/somedir/, eliminando efectivamente SSL!

El equilibrador de carga está enviando un X-Forwarded-Protoencabezado, pero no veo ninguna forma de que nginx lo consulte al diseñar su redirección; de hecho, hay una respuesta de 2012 que dice que nginx no puede hacer esto, y la solución es reemplazar el equilibrador de carga con nginx. En mi humilde opinión, esto es algo demasiado trivial para garantizar un cambio de pila tan drástico.

¿Ha cambiado algo desde 2012 aquí? Realmente no quiero reescribir estos redireccionamientos en el nivel HAProxy: los redireccionamientos HTTPS a HTTP reales intencionales desde la aplicación web podrían "re-HTTPSed" si siempre reescribo el esquema para que el Location:encabezado de respuesta sea el mismo que el esquema la solicitud fue hecha con.

EDITAR:

Aquí hay una configuración minimizada que muestra que nginx produce Location:URL absolutas . Tenga en cuenta que no hay reescrituras.

user nobody nobody;
worker_processes auto;
worker_rlimit_nofile 4096;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # TODO: Tune fastcgi_buffers/other buffers

    # Configure keepalive connections
    keepalive_timeout 15;
    keepalive_requests 1000;

    # Hide server version.
    server_tokens off;

    # Do not allow any directory indexes anywhere.
    # This is the default, but it is here for extra paranoia.
    autoindex off;

    # gzip text content.
    gzip on;
    gzip_vary on;
    gzip_disable "msie6";
    gzip_comp_level 2;
    gzip_min_length 1024;
    gzip_types  text/css
                text/plain
                text/xml
                application/json
                application/javascript;

    server {
        listen 8000 default_server;

        root /usr/share/nginx/html;
        index index.html index.htm;

        server_name localhost;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

Y si usa curl para ver los encabezados, tenga en cuenta que he creado un directorio testdiren /usr/share/nginx/html:

[myuser@dev nginx]$ curl -i http://localhost:8000/testdir
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 26 Mar 2015 14:35:49 GMT
Content-Type: text/html
Content-Length: 178
Location: http://localhost:8000/testdir/
Connection: keep-alive

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>

nginx wants to send an HTTP 301 redirect to an absolute URL- nginx no hace eso a menos que tenga una regla de reescritura explícita para hacerlo - muestre su configuración completa.
AD7six

Agregué la configuración, recortada para ilustrar este problema. No hago ninguna reescritura explícita.
mutron

1
Debe configurar su equilibrador para reemplazar el protocolo en el Location:encabezado ya que nginx no tiene idea de cuál era el protocolo original.
Alexey Ten

2
@AlexeyTen, ¿le gustaría publicar eso como respuesta para que pueda aprobarlo? Tampoco he encontrado una manera de hacer esto en nginx, por lo que un cambio en el equilibrador de carga parece ser la única forma.
mutron

1
¡Esto sigue siendo un error con la última versión de nginX! ¿Alguien sabe si ya hay un informe de error? No se pudo encontrar uno.
Roel van Duijnhoven

Respuestas:



-1

Usted necesita decir el equilibrador de carga para volver a escribir httpa httpslas solicitudes, así:

proxy_redirect http:// $scheme://;
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.