如何在nginx下修复Sinatra将https重定向到http的问题

14
我有一个在nginx中运行的Sinatra应用程序(使用thin作为后代理),我在Sinatra中使用redirect '/<path>'语句。然而,当我使用https访问网站时,这些重定向将我发送到http://localhost/<path>而不是https://localhost/<path>,这是它们应该做的。
目前,nginx使用proxy_pass http://thin_cluster命令将控制权传递给thin,其中thin_cluster是...
upstream thin_cluster { server unix:/tmp/thin.cct.0.sock; }

我该如何修复这个问题?


在你的 proxy_pass 行后面添加 proxy_set_header X-Forwarded-Proto $scheme; 有帮助吗? - matt
你应该将那写成答案……它解决了我的问题。谢谢! - Alex Mullans
2个回答

22
为了让Sinatra正确组装用于重定向的URL,它需要能够确定请求是否使用ssl,以便可以使用适当的httphttps进行重定向。
显然,实际调用thin时并未使用ssl,因为这是由前端Web服务器处理的,代理请求是明文的。因此,我们需要一种方法告诉Sinatra,即使它实际上没有使用ssl,也应将请求视为安全的。
最终确定请求是否应视为安全的代码在Rack :: Request#ssl?Rack :: Request#scheme方法中。 scheme方法检查env哈希表,看看是否存在多个条目之一。其中之一是HTTP_X_FORWARDED_PROTO,它对应于X-Forwarded-Proto HTTP标头。如果设置了此项,则该值用作协议方案(httphttps)。
如果我们在nginx代理请求到后端时添加这个HTTP头部,Sinatra将能够正确地确定何时重定向到https。在nginx中,我们可以使用proxy_set_header向代理请求添加头部,并且方案可以在$scheme变量中获得。因此,添加以下行:
proxy_set_header X-Forwarded-Proto $scheme;

proxy_pass行之后添加到nginx配置中应该使其正常工作。

由于某些原因,这导致我的标题中的“主机”字段出现问题,使我的所有redirect_to都指向无效域。添加“proxy_set_header Host $host”修复了这个问题。(我的应用程序在子URI下运行,我想知道那是否有问题。) - bioneuralnet
2
@bioneuralnet,您也可以使用X-Forwarded-Host,在检查Host头之前,Rack会对其进行检查。看起来nginx不会自动添加这些标头,但是Apache在mod_proxy中会添加。 - matt
1
是的,我认为那也可以。在http://wiki.nginx.org/HttpProxyModule#proxy_set_header上找到了一个有趣的解释。我在http块中设置了proxy_set_header Host,用于所有我的应用程序。根据您的帖子,在location @myapp中添加了proxy_set_header X-Forwarded-Proto。根据文档,“在更高级别发出的proxy_set_header指令仅在给定级别未发出proxy_set_header指令时继承。”因此,即使它们是针对不同字段的,@myapp中的“本地”proxy_set_header调用也会清除我的“全局”proxy_set_header调用。 - bioneuralnet

1

您可以在nginx层强制所有链接转到https。

在nginx.conf中:
server{
   listen 80;
   server_name example.com;
   rewrite    ^(.*) https://$server_name$1 redirect;
}    

这也很好,可以确保您的请求始终是https


这很有帮助...但并没有回答我提出的问题。如果服务器仅在HTTPS模式下运行,我已经使此功能正常工作;我的问题是当我想接受HTTPS和HTTP时发生的。 - Alex Mullans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接