我想将我的网络服务器上的所有 http 请求重写为 https 请求,我从以下内容开始:
服务器 { 听 80; 地点 / { 重写 ^(.*) https://mysite.com$1 永久; } ...
一个问题是这会剥离任何子域信息(例如,node1.mysite.com/folder),我如何重写以上内容以将所有内容重新路由到 https 并维护子域?
我想将我的网络服务器上的所有 http 请求重写为 https 请求,我从以下内容开始:
服务器 { 听 80; 地点 / { 重写 ^(.*) https://mysite.com$1 永久; } ...
一个问题是这会剥离任何子域信息(例如,node1.mysite.com/folder),我如何重写以上内容以将所有内容重新路由到 https 并维护子域?
新版本nginx的正确方法
结果我对这个问题的第一个答案在某些时候是正确的,但它变成了另一个陷阱 - 要保持最新状态,请检查Taxing rewrite pitfalls
我已经被许多 SE 用户更正,所以归功于他们,但更重要的是,这里是正确的代码:
注意:执行此操作的最佳方法由https://serverfault.com/a/401632/3641提供- 但在此重复:
在最简单的情况下,您的主机将被固定为您要将它们发送到的服务 - 这将执行 301 重定向到浏览器,并且浏览器 URL 将相应更新。
以下是之前的答案,由于正则表达式,效率低下,@kmindi 所示的简单 301 非常好
我一直在使用 nginx 0.8.39 及更高版本,并使用了以下内容:
向客户端发送永久重定向。
我认为最好也是唯一的方法应该是使用HTTP 301 Moved Permanently重定向,如下所示:
根据已经提到的pitfails , HTTP 301 Moved Permanently重定向也是最有效的,因为没有要评估的正则表达式。
新的HTTP 308 Moved Permanently保留了 Request 方法,并受到主流浏览器的支持。例如,使用
308
可防止浏览器将请求方法从POST
更改GET
为重定向请求。如果您想保留主机名和子域,这就是方法。
如果您没有 DNS ,这仍然有效,因为我也在本地使用它。例如,我请求
http://192.168.0.100/index.php
并将被重定向到完全https://192.168.0.100/index.php
。我
listen [::]:80
在我的主机上使用,因为我bindv6only
设置为false
,所以它也绑定到 ipv4 套接字。listen 80
如果您不想要 IPv6 或想在其他地方绑定,请将其更改为。Saif Bechan 的解决方案
server_name
在我的情况下使用的是 localhost 但无法通过网络访问。Michael Neale 的解决方案很好,但根据缺陷,重定向 301 有更好的解决方案;)
在服务器块中,您还可以执行以下操作:
以上不适用于一直创建的新子域。例如 AAA.example.com BBB.example.com 大约有 30 个子域。
终于得到了一个使用以下内容的配置:
很久很久以前,我对正确答案发表了评论,其中有一个非常重要的更正,但我觉得有必要在其自己的答案中突出这个更正。如果您在任何时候都设置了不安全的 HTTP 并期望用户内容、有表单、托管 API 或配置了任何网站、工具、应用程序或实用程序来与您的站点对话,那么之前的答案都不能安全使用。
POST
向您的服务器发出请求时会出现此问题。如果服务器使用普通30x
重定向响应,则 POST 内容将丢失。发生的情况是浏览器/客户端会将请求升级到 SSL,但将请求降级。参数将丢失,并且将向您的服务器发出不正确的请求。POST
GET
POST
解决方案很简单。您需要使用
HTTP 1.1 307
重定向。这在 RFC 7231 S6.4.7 中有详细说明:该解决方案改编自公认的解决方案,用于
307
您的重定向代码:我设法这样做:
https://stackoverflow.com/a/36777526/6076984
我在 AWS ELB 后面运行 ngnix。ELB 通过 http 与 ngnix 对话。由于 ELB 无法向客户端发送重定向,因此我检查 X-Forwarded-Proto 标头并重定向:
如果您
return 301 https://$host$request_uri;
作为端口 80 上的默认响应,那么您的服务器迟早会进入开放代理列表[1] 并开始被滥用以在 Internet 上的其他地方发送流量。如果您的日志中充满了这样的消息,那么您就知道它发生在您身上:问题是它
$host
会回显浏览器在Host
标头中发送的任何内容,甚至是 HTTP 开头行中的主机名,如下所示:由于这个问题,这里的一些其他答案建议使用
$server_name
而不是$host
.$server_name
总是评估你在server_name
声明中的内容。但是,如果您在那里有多个子域或使用通配符,那将不起作用,因为$server_name
只使用声明后的第一个条目server_name
,更重要的是只会回显通配符(而不是扩展它)。那么如何在保持安全性的同时支持多个域呢?在我自己的系统上,我通过首先列出一个
default_server
不使用的块来处理这个困境$host
,然后列出一个通配符块:(您还可以在第二个块中列出多个域。)
使用这种组合,不匹配的域将被重定向到硬编码的某个地方(总是
example.com
),并且与您自己的域匹配的域将转到正确的位置。您的服务器不会用作开放代理,因此您不会招来麻烦。如果你觉得不耐烦,我想你也可以让
default_server
区块不匹配你的合法域,并提供一些令人反感的东西。. . .[1] 从技术上讲,“代理”是错误的词,因为您的服务器不会出去并满足客户端的请求,只是发送重定向,但我不确定正确的词是什么。我也不确定目标是什么,但它会用噪音填满你的日志并消耗你的 CPU 和带宽,所以你不妨停止它。
似乎没有人真正做到 100% 正确。要让整个网络服务器的 80 端口请求转到它们的 443 等效项,您需要使用listen指令,而不是 server_name 指令来指定包罗万象的名称。另请参阅https://nginx.org/en/docs/http/request_processing.html
并确保检查 /etc/nginx/conf.d/ 中已有的内容,因为我经常遇到 default.conf 返回一些现有虚拟主机的问题。我处理 nginx 问题的顺序总是从移出默认文件开始,然后逐行注释掉它,看看哪里出了问题。