我想使用 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 实现任何功能,这将有助于排除故障。