在Nginx中,如何在维护子域的同时将所有http请求重写为https?

我想重写我的web服务器上的所有http请求是https请求,我开始以下内容:

服务器{
    听80;

    位置 / {
      重写^(。*)https://mysite.com$1永久;
     }
 ...

一个问题是,这剥离了任何子域信息(例如,node1.mysite.com/folder),我怎么能重写上述重新路由到https和维护子域?

在新版本的nginx中正确的方式

对于这个问题我的第一个答案在某些时候是正确的,但它变成了另一个陷阱 – 保持最新,请检查Taxing重写陷阱

我已经被许多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"; [....] } 

注意:最好的方法是通过https://serverfault.com/a/401632/3641提供 – 但在这里重复:

 server { listen 80; return 301 https://$host$request_uri; } 

在最简单的情况下,您的主机将被固定为您想要发送给他们的服务 – 这将301redirect到浏览器,浏览器URL将相应地更新。

下面是以前的答案,这是由于正则expression式效率低下,一个简单的301是伟大的,如@kmindi所示

我一直在使用nginx 0.8.39及以上版本,并使用了以下内容:

  server { listen 80; rewrite ^(.*) https://$host$1 permanent; } 

发送永久redirect到客户端。

我认为最好的和唯一的方法应该是使用HTTP 301 Moved永久redirect,如下所示:

 server { listen [::]:80; return 301 https://$host$request_uri; } 

根据已经提到的pitfails , HTTP 301 Moved永久redirect也是最有效的,因为没有正则expression式要评估。


新的HTTP 308永久移动保留了请求方法, 并被主stream浏览器所支持 。 例如,使用308可防止浏览器将请求方法从POST更改为GET以获取redirect请求。


如果你想保留主机名和子域,这是方式。

如果您没有DNS ,这仍然工作 ,因为我也在本地使用它。 我要求例如http://192.168.0.100/index.php ,并将redirect到完全https://192.168.0.100/index.php

我在我的主机上使用listen [::]:80 ,因为我将bindv6only设置为false ,所以它也绑定到ipv4套接字。 如果你不想要IPv6,或者想要绑定到其他地方,可以将其更改为listen 80

来自Saif Bechan的解决scheme使用server_name ,在我的情况下是localhost,但不能通过networking访问。

迈克尔·尼尔的解决scheme是好的,但根据pitfails,redirect301有一个更好的解决scheme;)

上面的内容并不适用于一直在创build新的子域。 例如AAA.example.com BBB.example.com约30个子域名。

最后得到一个configuration与以下工作:

 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 # ... } 

在服务器块内,您还可以执行以下操作:

 # Force HTTPS connection. This rules is domain agnostic if ($scheme != "https") { rewrite ^ https://$host$uri permanent; } 

很久很久以前,我在正确的答案上发表了一个非常重要的更正,但是我觉得有必要在自己的答案中突出这个更正。 如果您有任何不安全的HTTP设置并期望用户内容,表单,托pipeAPI或已configuration任何网站,工具,应用程序或实用程序与您的站点通话,则以前的答案都不可用。

POST请求发送到您的服务器时,会发生此问题。 如果服务器响应一个普通的30xredirect,POST内容将会丢失。 会发生什么是浏览器/客户端将请求升级到SSL,但 POST 降级GET请求。 POST参数将会丢失,并且会向您的服务器发出不正确的请求。

解决scheme很简单。 您需要使用HTTP 1.1 307redirect。 这在RFC 7231 S6.4.7中详细说明:

  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). 

该解决scheme根据公认的解决scheme进行调整,在redirect代码中使用307

 server { listen 80; server_name my.domain.com; return 307 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"; [....] } 

我在AWS ELB后面运行ngnix。 ELB正在通过http与ngnix交stream。 由于ELB无法发送redirect到客户端,我检查了X-Forwarded-Proto标题并redirect:

 if ($http_x_forwarded_proto != 'https') { return 301 "https://www.exampl.com"; } 

我设法做到这一点:

 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

 rewrite ^!https https://$host$request_uri permanent;