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

mut*_*ron 9 nginx haproxy

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

发生的事情示意图:

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

                      LOAD BALANCER                BACKENDS
Run Code Online (Sandbox Code Playgroud)

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

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

server {
    server_name frontend;
    ...
    try_files $uri $uri/ =404;
    ...
}
Run Code Online (Sandbox Code Playgroud)

现在,默认情况下,当我访问没有斜杠的目录时,例如https://frontend/somedir,nginx 想要将 HTTP 301 重定向发送到绝对 URL,例如http://frontend:8000/somedir/.

我可以让 nginx 省略 8000 端口号使用port_in_redirect off.

但是,我似乎无法http://在 nginx 生成的重定向开始时更正该方案。我可以让 nginx 做的最好的事情是从https://frontend/somedirto重定向http://frontend/somedir/,有效地剥离 SSL!

负载均衡器正在发送一个X-Forwarded-Proto标头,但我看不到 nginx 在制作重定向时有任何方式来查询它;事实上,2012 年有一个回答说nginx 完全不能做到这一点,解决方案是用 nginx 替换负载均衡器。恕我直言,这太微不足道了,无法保证如此剧烈的堆栈变化。

自 2012 年以来这里有什么变化吗?我真的不想在 HAProxy 级别重写这些重定向:如果我总是将Location:响应标头的方案重写为与方案相同,那么从 Web 应用程序实际有意的 HTTPS 到 HTTP 重定向可能会“重新 HTTPS”请求是用的。

编辑:

这是显示 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您使用 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>
Run Code Online (Sandbox Code Playgroud)

Dan*_*nin 5

快进到 2019 年,您可以:

absolute_redirect off; 
port_in_redirect off;
Run Code Online (Sandbox Code Playgroud)

来自文档absolute_redirect

如果禁用,nginx 发出的重定向将是相对的。


小智 -1

您需要告诉负载均衡器在请求中重写,如下所示httphttps

proxy_redirect http:// $scheme://;
Run Code Online (Sandbox Code Playgroud)