如何修复Heroku上Rails应用升级Redis后出现的OpenSSL::SSL::SSLError
问题背景
Rails应用部署在Heroku平台,Redis版本从4.0.14升级至6.2后,出现以下SSL错误:
OpenSSL::SSL::SSLError
SSL_connect returned=1 errno=0 peeraddr=108.128.159.63:20459 state=error: certificate verify failed (self signed certificate in certificate chain)
已尝试在config/initializers/redis.rb和config/cable.yml中设置verify_mode: OpenSSL::SSL::VERIFY_NONE跳过证书验证,但问题未解决。
解决方案步骤
1. 确认REDIS_URL协议头
Heroku Redis 6.2默认使用rediss://(带SSL加密)协议,而非旧版的redis://。如果环境变量中的REDIS_URL仍为redis://开头,会导致SSL配置不生效。
- 通过Heroku CLI检查当前URL:
heroku config:get REDIS_URL - 若URL不是
rediss://开头,重新绑定Heroku Redis插件或联系Heroku支持确认配置。
2. 升级Redis客户端版本
旧版redis-rb客户端对SSL参数的处理存在兼容性问题,需确保使用4.2.0及以上版本的redis gem:
- 在Gemfile中指定版本:
gem 'redis', '>= 4.2.0' - 执行更新并重新部署:
bundle update redis git commit -m "Upgrade redis gem to support SSL" git push heroku main
3. 修正Action Cable的SSL参数配置
config/cable.yml中verify_mode需传入整数值,而非Ruby常量名(ERB渲染后会输出常量字符串而非对应数值):
production: adapter: redis url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> channel_prefix: good_gym_production ssl_params: verify_mode: <%= OpenSSL::SSL::VERIFY_NONE.to_i %>
或直接使用对应整数0(VERIFY_NONE的数值为0):
production: adapter: redis url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> channel_prefix: good_gym_production ssl_params: verify_mode: 0
4. 覆盖所有Redis使用场景
检查应用中其他初始化Redis客户端的地方(如缓存、Sidekiq),确保统一添加SSL参数:
- 缓存配置(
config/environments/production.rb):config.cache_store = :redis_cache_store, { url: ENV["REDIS_URL"], ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } - Sidekiq配置(
config/initializers/sidekiq.rb):Sidekiq.configure_server do |config| config.redis = { url: ENV["REDIS_URL"], ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } end Sidekiq.configure_client do |config| config.redis = { url: ENV["REDIS_URL"], ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } end
5. 强制启用SSL
显式设置ssl: true确保客户端启用SSL,避免自动检测失败:
# config/initializers/redis.rb if Rails.env.test? require "mock_redis" REDIS = MockRedis.new else REDIS = Redis.new(url: ENV["REDIS_URL"], ssl: true, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }) end
验证
修改完成后重新部署应用,通过Heroku日志确认错误是否消失:
heroku logs --tail
内容的提问来源于stack exchange,提问作者DavidM

