server { listen 80; location / { rewrite ^(.*) https://mysite.com permanent; } ...
一个问题是,这剥夺了任何子域信息(例如,node1.mysite.com / folder),我如何重写以上内容以将所有内容重新路由到https并维护该子域?
#1 楼
在新版本的Nginx中正确的方法我对这个问题的第一个答案在某些时候是正确的,但它又变成了另一个陷阱-要保持最新状态,请检查对重写陷阱进行计税
许多SE用户已对我进行了更正,因此值得他们赞扬,但更重要的是,这里是正确的代码:
server {
listen 80;
server_name my.domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name my.domain.com;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000" always;
[....]
}
评论
但是,您必须逐域进行此操作-不?如果您想将其应用于服务器上的每个域怎么办?
– JM4
2012年8月15日23:57
@ JM4:如果您在重写中使用$ host $而不是server_name并将default_server添加到listen指令,则它将对您服务器上的每个域有效。
–克拉斯·范·舍尔文(Klaas van Schelven)
13年5月5日在20:06
重要的是要提到301存储在本地缓存中,没有到期日期。配置更改时不是很有用
– Trefex
15年4月10日在13:58
@everyone使用307重定向保留POST内容。
–马哈茂德·古德西(Mahmoud Al-Qudsi)
15年5月14日在16:46
请注意,如果您使用子域,则必须使用$ host而不是$ server_name。
– fish鱼
16年1月19日在14:27
#2 楼
注意:最佳方法是由https://serverfault.com/a/401632/3641提供的-但在此重复:server {
listen 80;
return 301 https://$host$request_uri;
}
如果您的主机将固定为您要发送给您的服务-这将执行301重定向到浏览器,并且浏览器URL将相应更新。
以下是上一个答案,即由于regex效率低下,因此@kmindi
显示了一个简单的301很好。我一直在使用nginx 0.8.39及更高版本,并使用以下代码:
server {
listen 80;
rewrite ^(.*) https://$host permanent;
}
发送永久重定向到客户端。
评论
我认为应该是80-因为它正在监听http,然后告诉客户端以https(443)的身份返回。
–迈克尔·尼尔(Michael Neale)
2011年12月8日在22:30
这应该是最佳答案!
–内森·斯托克斯(Nathan Stocks)
2012年8月31日在22:52
这是最费力的答案。
–案例
2012年11月21日在7:36
这是最简单的方法,但是最不安全-使用这种方法,您可以允许服务器将用户重定向到任何页面,而无需检查服务器是否允许使用该页面。如果您的服务器提供mydomain.co服务,恶意用户仍然可以使用您的服务器将用户重定向到其他域,例如mydomain.co,例如google.com。
–friedkiwi
13年5月30日在15:32
@ cab0lt此处没有安全问题。提供重定向不会带来安全风险。如果有访问控制要求,则应在浏览器请求新URL的位置进行检查。浏览器不会仅仅基于重定向来获得访问权限,也不需要重定向来请求新的URL。
–mc0e
13-10-16在3:38
#3 楼
我认为最好和唯一的方法应该是使用HTTP 301移动永久重定向,如下所示:server {
listen [::]:80;
return 301 https://$host$request_uri;
}
HTTP 301移动永久重定向也是最有效的,因为存在根据已经提到的pitfails,没有要评估的正则表达式。
新移动的HTTP 308永久保留了Request方法,并且受到主要浏览器的支持。例如,使用
308
可以防止浏览器将重定向请求的请求方法从POST
更改为GET
。如果要保留主机名和子域,则是这样。 >
如果您没有DNS,它仍然可以正常工作,因为我也在本地使用它。
我在主机上使用
http://192.168.0.100/index.php
,因为我将https://192.168.0.100/index.php
设置为listen [::]:80
,因此它也绑定到ipv4套接字。如果您不想使用IPv6或将其绑定到其他地方,请将其更改为bindv6only
。Saif Bechan的解决方案使用
false
,在我的情况下为localhost,但无法通过网络访问。 Michael Neale的解决方案很好,但是根据pitfails的说法,重定向301是一个更好的解决方案;)
评论
不错,您尝试引用它,但是301在HTTPS上不起作用。
–案例
2012年11月21日在7:34
什么不起作用?声明的服务器部分用于将未加密的HTTP(无s)流量永久重定向到加密的服务器(未列出侦听443(https)的部分)
–kmindi
2012年11月21日13:05
我检查了这对https和其他所有方法的效果是否都很好-@kmindi我参考您的回答更新了我的答案-因为我认为这是正确的方法,并且这种方法不断出现!辛苦了
–迈克尔·尼尔(Michael Neale)
13年6月4日,0:03
使用域(非IP)请求时,除非我将'[::]:80'更改为'80',否则它不起作用。
–约瑟夫·欲望
13年11月17日在19:58
可能是预期的行为:trac.nginx.org/nginx/ticket/345。我更新了答案以描述监听选项。
–kmindi
13年11月17日在20:35
#4 楼
在服务器块内,您还可以执行以下操作:# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}
评论
此配置导致我的服务器产生重定向循环
– Corkscreewe
2015年10月16日13:58
可能是因为存在其他重定向,或者您的网站/应用未启用https
– Oriol
2015年10月31日,下午3:59
除此一项外,其他任何一项似乎都不起作用。使用Nginx版本:Nginx / 1.10.0(Ubuntu)
– ThatGuy343
16年7月2日在1:22
为https:// $ host $ uri投票
–user138870
16年11月27日在17:12
如果您在负载均衡器后面,这就是方法!
–安特万
17年3月28日在19:50
#5 楼
上面的方法不适用于始终创建新的子域的情况。例如AAA.example.com BBB.example.com约有30个子域。
最后得到了可与以下内容一起使用的配置:
server {
listen 80;
server_name _;
rewrite ^ https://$host$request_uri? permanent;
}
server {
listen 443;
server_name example.com;
ssl on;
ssl_certificate /etc/ssl/certs/myssl.crt;
ssl_certificate_key /etc/ssl/private/myssl.key;
ssl_prefer_server_ciphers on;
# ...
# rest of config here
# ...
}
评论
谢谢! nginx将返回301 https:// * /或在此处的其他答案中过早取消请求。服务器名称 _; $ host是解决问题的答案。 +1
–坚果
13 Mar 13 '13 at 0:53
这是最优的!但是,我建议某些人将_替换为实际域,例如.domain.com我有两台服务器,nginx意外地将我的一台服务器定向到默认服务器。
– zzz
13年7月1日在21:16
这是唯一对我有用的答案,谢谢!
–雪人
16年7月21日在0:28
非常感谢伙伴。我尝试了许多解决方案,但没有解决。这个解决方案很棒,并且对我有用。服务器名称 _;这是什么意思。。我不明白。请给我解释一下。
– Pavan Kumar
17年1月11日14:51
#6 楼
很久很久以前,我就正确答案发表了评论,但有一个非常重要的更正,但我觉得有必要在自己的答案中突出此更正。如果您在任何时候都设置了不安全的HTTP并期望用户内容,具有表单,托管API或已配置了任何网站,工具,应用程序或实用程序来与您的站点对话,则上述任何答案都不能安全使用。 br />对服务器发出
POST
请求时,会发生问题。如果服务器使用简单的30x
重定向响应,则POST内容将丢失。发生的情况是浏览器/客户端将请求升级到SSL,但将POST
降级为GET
请求。 POST
参数将丢失,并且将向您的服务器发出错误的请求。解决方案很简单。您需要使用
HTTP 1.1 307
重定向。 RFC 7231 S6.4.7中对此进行了详细说明: br /> Note: This status code is similar to 302 (Found), except that it
does not allow changing the request method from POST to GET. This
specification defines no equivalent counterpart for 301 (Moved
Permanently) ([RFC7238], however, defines the status code 308
(Permanent Redirect) for this purpose).
#7 楼
我设法做到了:server {
listen 80;
listen 443 ssl;
server_name domain.tld www.domain.tld;
# global HTTP handler
if ($scheme = http) {
return 301 https://www.domain.tld$request_uri;
}
# global non-WWW HTTPS handler
if ($http_host = domain.tld){
return 303 https://www.domain.tld$request_uri;
}
}
https://stackoverflow.com/a/36777526/6076984
评论
没有IF的更新版本:paste.debian.net/plain/899679
– stamster
17年5月22日在10:52
#8 楼
我在AWS ELB后面运行ngnix。 ELB正在通过http与ngnix交谈。由于ELB无法将重定向发送到客户端,因此我检查了X-Forwarded-Proto标头并重定向:if ($http_x_forwarded_proto != 'https') {
return 301 "https://www.exampl.com";
}
#9 楼
如果将return 301 https://$host$request_uri;
作为端口80上的默认响应,则您的服务器可能迟早会出现在打开代理列表中[1],并开始被滥用以将流量发送到Internet上的其他地方。如果您的日志中充满了类似这样的消息,那么您知道它发生了:42.232.104.114 - - [25/Mar/2018:04:50:49 +0000] "GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1" 301 185 "http://www.ioffer.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; RogueCleaner; Alexa Toolbar)"
问题是
$host
会回显浏览器发送的任何内容Host
标头,甚至是HTTP开头行中的主机名,例如: $server_name
总是求值到$host
声明中的内容。但是,如果您在那里有多个子域或使用通配符,则将不起作用,因为$server_name
仅使用server_name
声明之后的第一个条目,更重要的是,仅回显通配符(而不扩展它)。 br />那么如何在保持安全性的同时支持多个域呢?在我自己的系统上,我首先通过列出了不使用$server_name
的server_name
块,然后列出了一个不使用default_server
的通配符块来解决这个难题:GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1
(您也可以在第二个块中列出多个域。)
通过这种组合,不匹配的域将被重定向到经过硬编码的位置(始终为
$host
),而与您自己的域匹配的域将转到右侧地点。您的服务器将无法用作开放代理,因此不会引起麻烦。如果您感到讨厌,我想您也可以使
example.com
块与您的合法域都不匹配并发动进攻。 。 。 。[1]从技术上讲,“ proxy”是一个错误的词,因为您的服务器不会关闭并满足客户端的请求,只是发送重定向,但我不确定哪个词是正确的。我也不确定目标是什么,但是它会充满噪音并消耗您的CPU和带宽,因此您最好停止它。
评论
关于代码返回301 https:// $ host $ request_uri,您是否有关于此类“开放代理”的先例; ?我喜欢创建一个通用块以将我的任何HTTP网站重定向到相同但HTTPS的想法。
– Alexey Vazhnov
3月30日18:36
#10 楼
rewrite ^!https https://$host$request_uri permanent;
#11 楼
似乎没人真的100%正确地做到了。要使端口80的请求到达整个Web服务器的443个等效端口,您需要使用listen指令,而不是server_name指令来指定全部捕获名称。另请参阅https://nginx.org/en/docs/http/request_processing.htmlserver { listen 80 default; listen [::]:80 default; return 307 https://$host$request_uri; }
$ host捕获子域名。
307和308都包含POST和GET请求URI。
307是临时的,经过全面测试后更改为永久308:
并确保检查/ etc / nginx / conf中已经存在的内容。 .d /,因为我经常会遇到default.conf返回一些现有虚拟主机的问题。我处理nginx问题的顺序始终是从移出默认文件开始,然后将其逐行注释掉,以查看出错的地方。
评论
请考虑将“接受的答案”移至serverfault.com/a/171238/90758。那是正确的。只需使用$ server_name而非硬编码的mysite.com