我有一个由 AWS ELB 负载均衡器后面的 nginx 提供服务的网站。负载均衡器上仅启用了 HTTPS。
请求单个文件或带有尾部斜杠的目录可以正常工作。但是,请求目录没有尾部斜杠不起作用。
原因是,当我请求没有尾部斜杠的目录时,nginx 会重定向到该路径和尾部斜杠(没问题),但它也会从 HTTPS 更改为 HTTP。负载均衡器配置为仅允许 HTTPS,因此这不起作用(超时)。
在 nginx 日志文件中,我可以看到请求到达 nginx,并且 nginx 使用 301 永久重定向进行响应(因此这不是负载均衡器设置的问题)。
10.100.10.15 - - [24/Nov/2017:15:41:08 +0000] "GET /admin HTTP/1.1" 301 178 "-" "Wget/1.18 (darwin16.0.0)"
当我通过以下方式请求 URL 时,curl
我看到重定向:
$ curl -v https://example.com/admin
* Trying 1.2.3.4...
* TCP_NODELAY set
* Connected to example.com (1.2.3.4) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: example.com
* Server certificate: Amazon
* Server certificate: Amazon Root CA 1
* Server certificate: Starfield Services Root Certificate Authority - G2
> GET /admin HTTP/1.1
> Host: example.com
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Date: Mon, 27 Nov 2017 09:19:05 GMT
< Content-Type: text/html
< Content-Length: 178
< Connection: keep-alive
< Server: nginx
< Location: http://example.com/admin/
< X-UA-Compatible: IE=Edge
<
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host example.com left intact
我的 nginx 配置文件如下
server {
root /var/www;
}
/etc/nginx/nginx.conf 是这里。
我已尝试过server_name_in_redirect off
,但并没有什么变化。
我想避免将主机名放在配置文件中,因为它会被打包到 Docker 映像中,然后部署在不同的主机上(QA、Prod 等)。
我希望 nginx 执行此重定向,但仍使用 HTTPS。我该怎么办?
答案1
修复该问题的最佳位置是 SSL 连接终止的地方。如果它正在运行nginx
,您将使用proxy_redirect
语句映射http
到标头https
中Location
。我不知道 AWS ELB,所以无法评论如何在那里修复它。
某些情况下会导致nginx
使用重定向进行响应,并且它假定该方案与用于连接它的方案相同(即来自 AWS ELB)。据我所知,有三种方法可以缓解后端nginx
服务器中的问题。
1)从 1.11.8 版本开始,该absolute_redirect off;
语句将导致Location
标头使用相对 URL,这意味着缺少方案和域名。
server {
absolute_redirect off;
...
}
看这个文件了解更多信息。
/
2)使用以下语句抑制在目录后附加尾随内容的行为try_files
:
server {
root /path/to/files;
location / {
try_files $uri =404;
}
...
}
看这个文件了解更多信息。
3)用明确的语句修复问题return
。
server {
root /path/to/files;
location ~ [^/]$ {
if (-d $request_filename) {
return 302 https://$host$uri/$is_args$args;
}
}
location / {
}
...
}
答案2
尝试这个
server {
root /var/www;
include /etc/nginx/basic.conf;
try_files $uri $uri/;
}
如果不起作用,请编辑您的问题以包含 basic.conf 和 nginx.conf 中的所有内容。另外,执行 curl 显示问题,包括响应标头和单个相应的 Nginx 访问日志文件。
答案3
你可以尝试使用“邪恶的如果”句子:
server {
...
if ($http_x_forwarded_proto = 'http' ) {
rewrite ^ https://$host$request_uri? permanent;
}
...
}
答案4
location
尚未在 AWS 上测试,但是我在每个块中都使用此行解决了问题:
proxy_redirect ~^http:(.*)$ https:$1;