nginx try_files перенаправляет по неверной схеме, когда стоит за балансировкой нагрузки завершения SSL (haproxy)

8

У меня есть сервер nginx 1.6.2, работающий в качестве бэкэнда за балансировщиком нагрузки, который выполняет завершение SSL. Все общение с внутренними серверами происходит по HTTP.

Схема того, что происходит:

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

                      LOAD BALANCER                BACKENDS

Для тестирования у меня только один бэкэнд на данный момент. Балансировщик нагрузки запускает HAProxy 1.5, над которым у меня есть некоторый контроль.

У меня есть довольно типичная try_filesдиректива в моем serverблоке в конфигурации бэкэнда nginx:

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

Теперь по умолчанию, когда я получаю доступ к каталогу без завершающей косой черты, например https://frontend/somedir, nginx хочет отправить перенаправление HTTP 301 на абсолютный URL-адрес, например http://frontend:8000/somedir/.

Я могу сделать nginx опустить номер порта 8000, используя port_in_redirect off.

Однако я не могу исправить http://схему в начале редиректа, который генерирует nginx. Лучшее , что я могу получить Nginx , чтобы сделать редирект от https://frontend/somedirк http://frontend/somedir/, эффективно вскрышных SSL!

Балансировщик нагрузки отправляет X-Forwarded-Protoзаголовок, но я не вижу возможности для nginx обратиться к нему при создании своего перенаправления; на самом деле есть ответ 2012 года о том, что nginx не может этого сделать, и решение состоит в том, чтобы заменить балансировщик нагрузки на nginx. ИМХО, это слишком тривиальная вещь, чтобы оправдать такое резкое изменение стека.

Здесь что-то изменилось с 2012 года? Я действительно не хочу переписывать эти перенаправления на уровне HAProxy: фактические преднамеренные перенаправления HTTPS на HTTP из веб-приложения могут получить «re-HTTPSed», если я просто всегда переписываю схему, чтобы Location:заголовок ответа совпадал со схемой запрос был сделан с.

РЕДАКТИРОВАТЬ:

Вот минимизированная конфигурация, показывающая, что nginx производит абсолютные Location:URL. Обратите внимание, что нет переписывает.

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

И если вы используете curl для просмотра заголовков - обратите внимание, я создал каталог testdirпод /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>
MuTron
источник
nginx wants to send an HTTP 301 redirect to an absolute URL- nginx не сделает этого, если у вас нет явного правила перезаписи, - пожалуйста, покажите свой полный конфиг.
AD7six
Я добавил конфиг, урезанный, чтобы просто проиллюстрировать эту проблему. Я не делаю никаких явных переписываний.
Мутрон
1
Вы должны настроить свой балансировщик так, чтобы он заменял протокол в Location:заголовке, поскольку nginx не имеет представления о том, какой протокол был оригинальным.
Алексей Тен
2
@AlexeyTen Вы хотели бы опубликовать это как ответ, чтобы я мог одобрить это? Я также не нашел способа сделать это в nginx, поэтому изменение балансировки нагрузки действительно кажется единственным способом.
Мутрон
1
Это все еще ошибка в последней версии nginX! Кто-нибудь знает, есть ли уже отчет об ошибке? Не смог найти.
Роэль ван Дуйнховен

Ответы:

2

Перемотка вперед до 2019 года, и вы можете:

absolute_redirect off; 
port_in_redirect off;

Из документов дляabsolute_redirect :

Если отключено, перенаправления, выпущенные nginx, будут относительными.

Данила Вершинин
источник
-1

Вы должны сказать балансировки нагрузки , чтобы переписать , httpчтобы httpsв запросах , как так:

proxy_redirect http:// $scheme://;
HostFission
источник