在 AWS EC2 上运行 Rails3,使用 force_ssl = true,使用 nginx,使用 ELB 终止 SSL,设置健康检查

在 AWS EC2 上运行 Rails3,使用 force_ssl = true,使用 nginx,使用 ELB 终止 SSL,设置健康检查

我想使用 SSL 运行我的整个 Rails 应用程序,所以我想使用 Rails 的全局 force_ssl 配置选项,它效果很好,但 ELB 的健康检查器永远不会工作,因为如果我将它设置为 http,Rails 将使用 301 转发到 https,并且健康检查将失败,因为它不是 200。如果我将它设置为 https,nginx/rails 将无法处理请求,因为 SSL 由 ELB 处理,而 nginx/rails 仅处理 HTTP。

global force_ssl我的非理想解决方案是对仅针对健康检查页面做出例外,但是 Rails 的global force_ssl配置总是会覆盖,force_ssl :except => :health_check所以这似乎不起作用。

另一个解决方案是不使用 ELB 进行 SSL 终止,并设置 HAProxy 等,但我想尽可能多地使用亚马逊的基础设施,以便更多地关注项目的核心开发而不是基础设施。

这是我的第一篇 serverfault 帖子,因此我非常感谢任何能给我的帮助(或我能提供的更多信息)。谢谢。

更新:

到目前为止,我通过让 ELB 通过只有它才能访问的 80 以外的其他端口访问 EC2 实例来“解决”这个问题,这感觉很极端,但保持了应用程序层和服务器层之间的分离。如果健康检查请求来自此端口的 ELB,nginx 将转发设置为“https”的 X-Forwarded-Proto 标头,这将让 Rack 认为它通过 SSL 传入,并让它通过。对于通过标准端口 80 传入的所有其他流量,它只会转发 ELB 提供的 X-Forwarded-Proto 标头,这将准确报告外部用户正在使用的内容,并让 Rails 决定是否强制使用 https。

仍在等待更清洁的解决方案,但这就是我所拥有的。

答案1

六个月后,这就是您的清洁解决方案。

# config/environments/production.rb
config.ssl_options = { exclude: proc { |env| env['PATH_INFO'].start_with?('/health_check') } }

答案2

需要注意的是,config.ssl_options 中的排除选项现已弃用,您必须使用 rack-ssl gem 获得相同的行为

对于我来说,仅仅为了健康检查而包含并初始化一个新的 rack 中间件似乎不是一个好主意,所以我决定使用 nginx 来为健康检查器设置 $http_x_forwarded_proto 标头。

以下是我的想法:

location @unicorn {

  if ($http_user_agent ~ "ELB-HealthChecker")
  {
    set $http_x_forwarded_proto https;
  }

  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
  proxy_set_header Host $http_host;
  proxy_redirect off;
  proxy_pass http://unicorn;
}

现在 rails 将 Health Checker 请求视为 https(尽管事实并非如此)并返回成功。

答案3

经过几天与配置等的角力后,我发现了这颗宝石:

https://github.com/lserman/aws-healthcheck

无需任何自定义 nginx 设置(它通过 rack 工作)。它返回200/healthcheck,效果非常好。只需将其添加到您的 gem 中即可。

答案4

如果你实际上并不关心你的健康检查是否影响你的 Rails 应用程序(你可能应该关心...),那么你可以将其指向一个静态文件,比如 /robots.txt,并使用 HTTP / 80 而不是 HTTPS / 443。Nginx 将提供静态文件,而无需涉及 Rails。

我并不是真的推荐长期这样做,但如果您难以通过 ELB 实现任何功能,这将有助于排除故障。

相关内容