Heroku环境下Sidekiq连接Redis出现127.0.0.1连接失败与SSL证书验证失败问题排查
故障排查与修正方案
常见故障点定位
1. Sidekiq连接地址指向127.0.0.1:6372的排查
- 首先确认
config/initializers/sidekiq.rb的文件路径是否正确:如果自定义配置文件放在config目录下但没有放在initializers子目录,Rails初始化时不会加载该文件,Sidekiq启动时会直接使用默认的本地回环Redis地址,不会读取你自定义的生产环境连接配置。校验方法:在Heroku生产控制台执行
Rails.application.initializers.select { |i| i.name.include?("sidekiq") }.map(&:name),如果返回结果为空,说明配置文件路径错误。 - 检查自定义URI修改逻辑的副作用:你现在用
URI.parse(ENV["REDIS_URL"])直接修改对象的scheme和端口,这个URI对象是对环境变量解析结果的引用,如果其他初始化代码提前读取了该URI对象做了修改,会导致最终拼接的连接地址和预期不一致。 - 核对
bin/start-stunnel脚本的实际逻辑:如果stunnel启动时会把环境变量中的REDIS_URL替换为本地回环的转发端口(比如6372),而你在Sidekiq配置里强行把原始端口+1、指定rediss协议,就会绕开stunnel的本地转发链路,要么连接到不存在的本地端口,要么直连公网Redis地址触发SSL校验问题。
2. 证书校验失败的排查
- 排除redis-rb 4.2.5的已知参数覆盖bug:这个版本的
:ruby驱动在检测到rediss://协议时,会自动生成默认的SSL配置,直接覆盖你手动传入的ssl_params参数——哪怕你写了verify_mode: VERIFY_NONE,实际连接时还是会走默认的严格证书校验,这是你配置了忽略证书但还是报SSL错误的核心原因。 - 移除多余的端口偏移逻辑:Heroku当前的Redis服务已经在环境变量给出的原端口上同时支持明文和SSL连接,不需要手动给端口+1。你现在加的
url.port = Integer(url.port) + 1是多年前老版本Heroku Redis需要单独开通SSL端口的遗留逻辑,现在执行这个操作只会连到错误的端口,根本到不了实际的Redis服务。校验方法:在Heroku控制台执行下面的命令,如果返回
PONG,说明端口偏移逻辑完全多余:Redis.new(url: ENV["REDIS_URL"], ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }).ping - 检查环境变量里的URL格式:你现在写的环境变量值已经带了
rediss://开头,不需要再手动把URI的scheme改成rediss,重复修改协议标识反而会让连接逻辑混乱。
可直接落地的修正配置
- 调整
config/initializers/sidekiq.rb,移除多余的端口和scheme修改逻辑,强制指定SSL参数优先级:
require 'sidekiq' Sidekiq.configure_client do |config| Sidekiq::Status.configure_client_middleware config, expiration: 30.minutes if Rails.env.production? config.redis = { url: ENV.fetch("REDIS_URL"), network_timeout: 5, ssl: true, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } end end Sidekiq.configure_server do |config| Sidekiq::Status.configure_server_middleware config, expiration: 30.minutes Sidekiq::Status.configure_client_middleware config, expiration: 30.minutes if Rails.env.production? config.redis = { url: ENV.fetch("REDIS_URL"), network_timeout: 5, ssl: true, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } end end
- 调整
config/initializers/redis.rb,去掉可变URI修改逻辑:
$redis = Redis.new( url: ENV.fetch("REDIS_URL"), driver: :ruby, ssl: true, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } )
- 修正
Procfile配置:既然已经通过原生rediss协议直连Heroku Redis,不需要对worker进程启动stunnel做本地转发,减少不必要的链路跳转:
release: bin/rails db:migrate web: bin/start-stunnel bin/rails server -p ${PORT:-5000} -e $RAILS_ENV worker: bundle exec sidekiq
- 版本兼容调整:建议将redis-rb版本从4.2.5升级到4.4.0及以上版本,修复旧版本中
ssl_params被默认配置覆盖的bug,避免手动配置的参数不生效。
内容的提问来源于stack exchange,提问作者ToddT
相关产品推荐
相关产品推荐

