将所有的http请求重定向到Amazon ELB后面的https,而不使用if语句。

目前,我有一个ELB同时为http://www.example.orghttps://www.example.org提供服务。

我希望设置这样的方式,即将任何指向http://www.example.org的请求重定向到https://www.example.org

ELB将https请求发送为http请求,因此使用:

server {
      listen         80;
       server_name    www.example.org;
       rewrite        ^ https://$server_name$request_uri? permanent;
}

不会起作用,因为对https://www.example.org的请求仍然会发送到nginx的80端口。

我知道可以将其重写为

server {
      listen         80;
      server_name    www.example.org;
      if ($http_x_forwarded_proto != "https") {
          rewrite ^(.*)$ https://$server_name$1 permanent;
      }
}
但是我读到的所有资料都说在nginx配置中应该尽量避免使用if,而且这适用于每个请求。此外,这意味着我必须为健康检查设置一个特殊的独立配置(如这里所描述的:“...当您位于ELB后面时,ELB充当HTTPS端点,并仅将HTTP流量发送到您的服务器,这会破坏ELB需要的健康检查的HTTP 200 OK响应能力。”)。 我正在考虑将登录放在Web应用程序的代码中,而不是nginx配置中(假设这是基于Django的应用程序),但我不确定这是否比配置中的if更加繁琐。

你好,请问你能告诉我这些代码放在哪里吗? - YuAn Shaolin Maculelê Lai
@YuAnShaolinMaculelêLai 当然可以。这些是nginx的配置文件,所以我只需将代码放入/etc/nginx/conf.d/目录下的一个文件中即可。通常我会将文件命名为domainname.conf,其中"domainname"是所讨论网站的域名。您可以根据需要自由命名该文件,只要确保以.conf结尾即可。 - Jordan Reiter
非常感谢。我尝试创建一个以.conf结尾的新文件,但对我来说没有起作用。然后我将代码放入AWS生成的文件中,位于/etc/nginx/conf.d/。现在它可以工作了。 - YuAn Shaolin Maculelê Lai
4个回答

1. 将您的AWS ELB设置为将ELB:80映射到实例:80,以及ELB:443映射到实例:1443。 2. 将nginx绑定到监听端口80和1443。 3. 将到达端口80的请求转发到端口443。 4. 健康检查应为HTTP:1443。它会拒绝HTTP:80,因为存在301重定向。

aws elb setup

NGINX设置
    server {
       listen         80;
       server_name    www.example.org;
       rewrite        ^ https://$server_name$request_uri? permanent;
    }

    server {
       listen         1443;
       server_name    www.example.org;
   } 

健康检查设置怎么样?您能详细说明一下吗? - samkhan13
这个在健康检查设置为 http:80 时无法运行,健康检查失败。 - samkhan13
2健康检查应该是HTTP:1443。它会拒绝HTTP:80,因为有301重定向。 - cbron
这对我来说大部分都有效,但是重写行在我的通配符域名上没有起作用。这篇其他的帖子修复了这个问题:http://serverfault.com/questions/447258/redirect-wildcard-subdomains-to-https-nginx/518385#518385 - Ron

如果它像那样正常工作,就不要害怕它。请注意,if的行为并不是不一致的,对于两个相同的请求,它不会在一个上随机失败,在另一个上正常工作,只要进行适当的测试和理解,if可以使用。尽管如此,仍然强烈建议在有其他指令可用的情况下使用它们。

这个页面还说了“如果在位置上下文中使用有问题”。在我看来,你可以在server {}而不是location {}之外完成你需要做的事情。(但如果我理解错了,请告诉我!) - Excalibur

这个解决方案使用了条件逻辑,但正如被接受的答案所建议的那样,我也认为这是可以的。参考:https://stackoverflow.com/questions/4833238/nginx-conf-redirect-multiple-conditions 此外,在AWS安全设置中不需要打开任何额外的端口来使用该镜像。您可以在AWS负载均衡器中终止SSL,并将HTTPS流量路由到实例上的HTTP端口80。 在这个示例中,负载均衡器的健康检查会访问端口80上的/health路径,然后将请求转发给应用服务器,因此健康检查验证了Nginx和您的应用程序都在正常运行。
server {
  listen 80 default deferred;

  set $redirect_to_https 0;
  if ($http_x_forwarded_proto != 'https') {
    set $redirect_to_https 1;
  }
  if ($request_uri = '/health') {
    set $redirect_to_https 0;
  }
  if ($redirect_to_https = 1) {
    rewrite ^ https://www.example.com$request_uri? permanent;
  }
  ...
}

1有一种更优雅的方式来完成这件事。 - Edward

现在您可以在AWS负载均衡器设置中创建一个新的监听器,将HTTP端口80重定向到HTTPS端口443。这样您就不需要再去修改nginx/apache配置了。

很遗憾,它目前还不支持在Cloudformation中。 - Aryeh Leib Taurog