在SSL终止负载平衡器(haproxy)后面时,nginx try_files使用错误的方案进行重定向


8

我有一个nginx 1.6.2服务器,作为后端执行SSL终止的负载平衡器。与后端服务器的所有通信均通过HTTP。

发生的情况的图表:

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

                      LOAD BALANCER                BACKENDS

出于测试目的,目前我只有一个后端。负载平衡器运行HAProxy 1.5,我可以控制它。

我在后端nginx配置中的块中有一个非常典型的try_files指令server

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/somedirhttp://frontend/somedir/有效地剥离SSL!

负载平衡器正在发送X-Forwarded-Proto标头,但是在设计其重定向时,nginx找不到任何方式来查询它;实际上,有一个2012年的回答说nginx不能完全做到这一点,解决方案是用nginx替换负载平衡器。恕我直言,这太琐碎了,以至于不能保证如此大的堆叠变化。

自2012年以来,这里有什么变化吗?我并不是真的想在HAProxy级别上重写这些重定向:从Web应用程序到HTTP重定向的实际故意HTTPS可能会获得“ 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>

nginx wants to send an HTTP 301 redirect to an absolute URL-除非您有明确的重写规则,否则nginx不会这样做-请显示完整的配置。
AD7six

我添加了配置,并进行了精简,以说明此问题。我不做任何明确的重写。
mutron 2015年

1
您应该配置您的平衡器以替换Location:标头中的协议,因为nginx不知道什么是原始协议。
阿列克谢2015年

2
@AlexeyTen您想将其发布为答案,以便我批准吗?我也没有在nginx中找到执行此操作的方法,因此在负载平衡器上进行更改确实确实是唯一的方法。
mutron 2015年

1
最新的nginX版本仍然是一个错误!有人知道是否已经有错误报告吗?找不到一个。
Roel van Duijnhoven

Answers:



-1

您需要告诉负载平衡器在请求中重写httphttps

proxy_redirect http:// $scheme://;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.