Rails 生产在 AWS 负载均衡器中不起作用
Rails production not work in AWS load balancer
我的 Rails 6 应用程序在 EC2 实例中的开发模式下运行良好。但是当配置使用生产模式时。负载均衡器无法进行健康检查,也无法 运行 应用程序。
我的健康检查:
安全:负载均衡器
安全性:Rails 个应用程序
负载均衡器在开发中工作
此处使用负载均衡器进行开发
开始 rails:
rails s -p 3000 -b 0.0.0.0
然后回复
=> Booting Puma
=> Rails 6.0.3.2 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.5 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
config/environments/development.rb
Rails.application.configure do
config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" #This is public dns of load balance
config.cache_classes = false
config.eager_load = false
config.consider_all_requests_local = true
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
config.action_mailer.raise_delivery_errors = false
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.perform_caching = false
config.active_support.deprecation = :log
config.assets.debug = true
config.assets.quiet = true
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end
下面是生产(不工作)
config/environments/production.rb
开始 rails:
RAILS_ENV=production rails s -p 3000 -b 0.0.0.0
然后回复:
=> Booting Puma
=> Rails 6.0.3.2 application starting in production
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.5 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: production
* Listening on tcp://0.0.0.0:3000
Rails.application.configure do
config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" #This is public dns of load balance
config.hosts << "3.14.65.84"
config.cache_classes = true
config.eager_load = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.assets.compile = false
config.log_level = :debug
config.log_tags = [ :request_id ]
config.action_mailer.perform_caching = false
config.i18n.fallbacks = true
config.active_support.deprecation = :notify
config.log_formatter = ::Logger::Formatter.new
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
end
负载均衡器:健康检查不工作!
我也试过:
- 将config/environments/development.rb复制到production.rb然后运行作为生产环境结果=====> Health Check Not Work!
- 将config/environment/production.rb复制到development.rb然后运行作为开发环境结果=====> Health Check Work!
似乎与 rails 配置无关,但它在 AWS 中处理生产的方式
帮助:如何使这个 Rails6 在带有负载均衡器的 AWS EC2 中作为生产环境工作?
我认为如果您创建自己的应用程序健康检查路由,而不是 ping 到根路径会更好:
# controller
class HealthCheckController < ApplicationController
def show
render body: nil, status: 200
end
end
# routes
get '/health_check', to: 'health_check#show'
然后将 LB 健康检查中的 ping 路径更新为 /health_check
编辑:
在生产配置文件中添加 config.hosts.clear
替换 config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com"
以使 rails 接受请求
我的公司刚刚 运行 遇到了一个听起来非常相似的问题。一旦 ECS 启动任务,我们就可以通过 ELB 访问 Rails 应用程序,但是健康检查会失败,它会自动关闭它尝试启动的每个容器。
我们最终将 IP 运行ge 添加到主机配置中。在生产中完全禁用它感觉不对,所以我们得出了类似的结果:
config.hosts = [
"publicdomain.com",
"localhost",
IPAddr.new("10.X.X.X/23")
]
列入白名单的 IP 地址与 ECS 在容器中创建和插入时将使用的 运行ge 匹配。希望对您有所帮助!
此处缺少的信息是 Rails 默认情况下不会在生产中设置 config.hosts
。 config.hosts
的目的是防止由于存在 web-console
.
而在开发环境中重新绑定 DNS
这是我找到的关于该主题的最佳文章:https://prathamesh.tech/2019/09/02/dns-rebinding-attacks-protection-in-rails-6/
对于我们来说,我们在 application.rb 中为我们的主域和子域设置了 config.hosts
,然后在所有其他环境中对其进行了自定义。因此,这会导致 config.hosts
在生产中强制执行,然后 OP 观察到的 AWS 健康检查失败。
您有两个选择:
- 在生产中完全删除
config.hosts
。由于这不是由 Rails 默认设置的,因此假设 DNS 重新绑定攻击在产品中不是问题。
- 确定production.rb中的请求ip。上述解决方案将应用程序绑定到不好的基础架构。如果您想将应用程序部署到新区域怎么办?您可以动态或静态地执行此操作。
- 静态:设置环境变量以获取 ELB 请求 ip 地址。如果您使用的是 AWS,希望您使用的是 CloudFormation,这样您就可以将适当的值作为 ENV 或 ParameterStore 变量传递。
- 动态:使用 AWS Ruby SDK 获取 ELB ip 地址
对于遇到此问题的人来说,这里是另一个:https://discuss.rubyonrails.org/t/feature-proposal-list-of-paths-to-skip-when-checking-host-authorization/76246
今天遇到了同样的问题。就我而言,我只是降低了标准以接受 403 是健康的。这并不理想,但我们不应该牺牲主机保护或为可预测的 IP 广泛开放它。
更新 1:
Rails 已经支持从 6.1
中排除配置
config.host_authorization = { exclude: ->(request) { request.path =~ /healthcheck/ } }
参考:https://api.rubyonrails.org/classes/ActionDispatch/HostAuthorization.html
主要原因是从目标组到健康检查容器的连接使用 IP,而不是域,所以 rails 响应 403。
接受 403 或将其从主机授权中排除。
我的 Rails 6 应用程序在 EC2 实例中的开发模式下运行良好。但是当配置使用生产模式时。负载均衡器无法进行健康检查,也无法 运行 应用程序。
我的健康检查:
安全:负载均衡器
安全性:Rails 个应用程序
负载均衡器在开发中工作
此处使用负载均衡器进行开发
开始 rails:
rails s -p 3000 -b 0.0.0.0
然后回复
=> Booting Puma
=> Rails 6.0.3.2 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.5 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
config/environments/development.rb
Rails.application.configure do
config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" #This is public dns of load balance
config.cache_classes = false
config.eager_load = false
config.consider_all_requests_local = true
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
config.action_mailer.raise_delivery_errors = false
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.perform_caching = false
config.active_support.deprecation = :log
config.assets.debug = true
config.assets.quiet = true
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end
下面是生产(不工作)
config/environments/production.rb
开始 rails:
RAILS_ENV=production rails s -p 3000 -b 0.0.0.0
然后回复:
=> Booting Puma
=> Rails 6.0.3.2 application starting in production
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.5 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: production
* Listening on tcp://0.0.0.0:3000
Rails.application.configure do
config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" #This is public dns of load balance
config.hosts << "3.14.65.84"
config.cache_classes = true
config.eager_load = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.assets.compile = false
config.log_level = :debug
config.log_tags = [ :request_id ]
config.action_mailer.perform_caching = false
config.i18n.fallbacks = true
config.active_support.deprecation = :notify
config.log_formatter = ::Logger::Formatter.new
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
end
负载均衡器:健康检查不工作!
我也试过:
- 将config/environments/development.rb复制到production.rb然后运行作为生产环境结果=====> Health Check Not Work!
- 将config/environment/production.rb复制到development.rb然后运行作为开发环境结果=====> Health Check Work!
似乎与 rails 配置无关,但它在 AWS 中处理生产的方式
帮助:如何使这个 Rails6 在带有负载均衡器的 AWS EC2 中作为生产环境工作?
我认为如果您创建自己的应用程序健康检查路由,而不是 ping 到根路径会更好:
# controller
class HealthCheckController < ApplicationController
def show
render body: nil, status: 200
end
end
# routes
get '/health_check', to: 'health_check#show'
然后将 LB 健康检查中的 ping 路径更新为 /health_check
编辑:
在生产配置文件中添加 config.hosts.clear
替换 config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com"
以使 rails 接受请求
我的公司刚刚 运行 遇到了一个听起来非常相似的问题。一旦 ECS 启动任务,我们就可以通过 ELB 访问 Rails 应用程序,但是健康检查会失败,它会自动关闭它尝试启动的每个容器。
我们最终将 IP 运行ge 添加到主机配置中。在生产中完全禁用它感觉不对,所以我们得出了类似的结果:
config.hosts = [
"publicdomain.com",
"localhost",
IPAddr.new("10.X.X.X/23")
]
列入白名单的 IP 地址与 ECS 在容器中创建和插入时将使用的 运行ge 匹配。希望对您有所帮助!
此处缺少的信息是 Rails 默认情况下不会在生产中设置 config.hosts
。 config.hosts
的目的是防止由于存在 web-console
.
这是我找到的关于该主题的最佳文章:https://prathamesh.tech/2019/09/02/dns-rebinding-attacks-protection-in-rails-6/
对于我们来说,我们在 application.rb 中为我们的主域和子域设置了 config.hosts
,然后在所有其他环境中对其进行了自定义。因此,这会导致 config.hosts
在生产中强制执行,然后 OP 观察到的 AWS 健康检查失败。
您有两个选择:
- 在生产中完全删除
config.hosts
。由于这不是由 Rails 默认设置的,因此假设 DNS 重新绑定攻击在产品中不是问题。 - 确定production.rb中的请求ip。上述解决方案将应用程序绑定到不好的基础架构。如果您想将应用程序部署到新区域怎么办?您可以动态或静态地执行此操作。
- 静态:设置环境变量以获取 ELB 请求 ip 地址。如果您使用的是 AWS,希望您使用的是 CloudFormation,这样您就可以将适当的值作为 ENV 或 ParameterStore 变量传递。
- 动态:使用 AWS Ruby SDK 获取 ELB ip 地址
对于遇到此问题的人来说,这里是另一个:https://discuss.rubyonrails.org/t/feature-proposal-list-of-paths-to-skip-when-checking-host-authorization/76246
今天遇到了同样的问题。就我而言,我只是降低了标准以接受 403 是健康的。这并不理想,但我们不应该牺牲主机保护或为可预测的 IP 广泛开放它。
更新 1:
Rails 已经支持从 6.1
中排除配置config.host_authorization = { exclude: ->(request) { request.path =~ /healthcheck/ } }
参考:https://api.rubyonrails.org/classes/ActionDispatch/HostAuthorization.html
主要原因是从目标组到健康检查容器的连接使用 IP,而不是域,所以 rails 响应 403。 接受 403 或将其从主机授权中排除。