在 AWS ECS 上设置 Rails 6 的正确方法

Proper way to set up Rails 6 on AWS ECS

我在 AWS ECS 上部署了 Rails 6 (运行 Puma)。有一个 ECS 服务和一个 ECS 任务,该任务启动托管我的应用程序的 EC2 实例。我还使用我的 ECS 服务创建了一个 Application Load Balancer。我向负载均衡器添加了一个 HTTPS 侦听器。我的听众指向一个目标组,该目标组专门通过 HTTP 协议接受流量。

我对请求流程的理解:

HTTPS request from internet:
  --> hits AWS load balancer 
    --> hits HTTPS listener
      --> passes traffic using HTTP to Target Group
        --> request finally reaches Rails app on Target Group EC2 targets *over HTTP*

这是一个有效的设置吗?我读了这篇文章 ,我的解释是我们的负载均衡器只需要 HTTPS 而不是 Puma,因此也不需要 Target Group。

我还通过 HTTP 为我的目标组设置了健康检查,该目标组期望将 301 状态代码响应作为健康目标(因为我的 Rails 配置中启用了 config.force_ssl)。问题是,为什么来自负载均衡器的流量没有被重定向?为什么来自健康检查的流量会被重定向?他们不是都针对同一个目标群体吗?为什么一个请求结果为 200 而另一个请求结果为 301?

我画了一张图来表达我的 question/confusion/current 理解:

这是我的负载均衡器和目标组设置:

不确定这是 AWS 问题还是 Puma 问题或其他问题。采纳所有想法!谢谢!!

回答你的 2 个问题。

  1. 为什么来自负载均衡器的流量没有被重定向?

This answer 也对此进行了解释,但我会更深入地挖掘:当负载均衡器接收到 HTTPS 连接并通过 HTTP 将其转发到您的 Rails 服务器时,它将设置X-FORWARDED-PROTO=https header 到请求,并且 Rails 理解这对于 force_ssl 配置来说已经足够了。

代码路径是Rails https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/middleware/ssl.rb(根据该文件中的注释,当 config.force_ssl 为真时包含在请求链中)将调用 request.ssl?

request 在该上下文中是 https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/http/request.rb 的实例,但您不会在其中找到定义的 ssl? 方法;但是,class 包括 include Rack::Request::Helpers.

如果你查看 Rack 的源代码,你会发现 https://github.com/rack/rack/blob/master/lib/rack/request.rb 中定义的 ssl? 方法调用了 scheme 方法,而 X-Forwarded-Proto header 将在 elsif forwarded_scheme 部分进行检查。好了 :) 即使它是一个 HTTP 请求,header 的存在也会使 request.ssl? return 为真。

  1. 为什么来自健康检查的流量会被重定向?

在这种情况下,它是从负载平衡器到您的应用程序的 HTTP 请求,不包含 X-Forwarded-For 或 X-Forwarded-Proto header,因此 Rail 的 config.force_ssl正在做它应该做的事情并重定向。

最后,查看 config.force_ssl 上的 documentation。您实际上可以将其设置为选项的哈希值,并从 force_ssl 行为中排除您的健康检查网址!

config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } }