关于ruby:如何解决错误“缺少’secret_key_base`为’生产’环境”(Rails 4.1)

How to solve error “Missing `secret_key_base` for 'production' environment” (Rails 4.1)

我从头开始创建了一个rails应用程序(rails 4.1),我遇到了一个我无法解决的奇怪问题。

每次我尝试在Heroku上部署我的应用程序时,都会收到错误500:

Missing secret_key_base for 'production' environment, set this value in config/secrets.yml

secret.yml文件包含以下配置:

1
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

在Heroku上,我已经使用"rake secret"命令的结果配置了一个环境变量"SECRET_KEY_BASE"。 如果我启动"heroku config",我可以看到具有正确名称和值的变量。

为什么我仍然会收到此错误?

非常感谢


我遇到了同样的问题,我通过创建一个环境变量来解决它,每次登录到生产服务器时都会加载它并制作一个配置它的步骤的迷你指南:

https://gist.github.com/pablosalgadom/4d75f30517edc6230a67

我正在使用Rails 4.1和Unicorn v4.8.2,当我尝试部署我的应用程序时,它没有正确启动,在unicorn.log文件中我发现此错误消息:

app error: Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml` (RuntimeError)

经过一些研究后我发现Rails 4.1改变了管理secret_key的方式,所以如果你读了位于exampleRailsProject/config/secrets.yml的secrets.yml文件,你会发现这样的东西:

1
2
3
4
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

这意味着Rails建议您在生产服务器中为secret_key_base使用环境变量,为了解决此错误,您应该按照以下步骤在生产服务器中为Linux(在我的例子中为Ubuntu)中创建环境变量:

  • 在生产服务器的终端中执行下一个命令:

    1
    $ RAILS_ENV=production rake secret

    这将返回一个包含字母和数字的大字符串,复制该字符串(我们将该代码称为GENERATED_CODE)。

  • 登录您的服务器

    • 如果以root用户身份登录,请找到此文件并进行编辑:

      1
      $ vi /etc/profile

      转到文件的底部(VI中的大写字母G的"SHIFT + G")

      使用GENERATED_CODE编写环境变量(按"i"键在VI中写入),请确保在文件末尾的新行中:

      1
      $ export SECRET_KEY_BASE=GENERATED_CODE

      保存更改并关闭文件(按"ESC"键,然后写入":x"和"ENTER"键进行保存,然后退出VI)。

    • 但是,如果您以普通用户身份登录,请将此名称称为"example_user",您需要找到以下其中一个文件:

      1
      2
      3
      $ vi ~/.bash_profile
      $ vi ~/.bash_login
      $ vi ~/.profile

      这些文件按重要性排序,这意味着如果您有第一个文件,那么您就不需要写入其他文件。因此,如果您在目录~/.bash_profile~/.profile中找到了这两个文件,则只需要在第一个~/.bash_profile中写入,因为Linux将只读取此文件而另一个将被忽略。

      然后我们转到文件的底部(VI中的大写字母G的"SHIFT + G")。

      我们将使用GENERATED_CODE编写环境变量(按"i"键在VI中写入),请确保在文件末尾的新行中:

      1
      $ export SECRET_KEY_BASE=GENERATED_CODE

      编写代码后,保存更改并关闭文件(按"ESC"键然后写入":x"和"ENTER"键进行保存并退出VI)。

  • 您可以使用以下命令验证我们的环境变量是否在Linux中正确设置:

    1
    $ printenv | grep SECRET_KEY_BASE

    或者:

    1
    $ echo $SECRET_KEY_BASE

    执行此命令时,如果一切正常,它将显示之前的GENERATED_CODE。最后完成所有配置后,您应该可以使用Unicorn或其他方式部署没有问题的Rails应用程序。

  • 当您关闭shell终端并再次登录到生产服务器时,您将设置此环境变量并准备使用它。

    就是这样!!我希望这个迷你指南可以帮助您解决此错误。

    免责声明:我不是Linux或Rails大师,所以如果您发现错误或任何错误,我将很乐意解决它!


    我假设您没有将secrets.yml检入源代码控制(即它位于.gitignore文件中)。即使这不是你的情况,也是许多观看这个问题的人所做的事情,因为他们的代码暴露在Github上并且不希望他们的密钥浮动。

    如果它不在源代码管理中,Heroku不知道它。因此Rails正在寻找Rails.application.secrets.secret_key_base并且它尚未设置,因为Rails通过检查不存在的secrets.yml文件来设置它。简单的解决方法是进入config/environments/production.rb文件并添加以下行:

    1
    2
    3
    4
    5
    Rails.application.configure do
        ...
        config.secret_key_base = ENV["SECRET_KEY_BASE"]
        ...
    end

    这告诉应用程序使用环境变量设置密钥,而不是在secrets.yml中查找它。这样可以节省我很多时间来预先了解这一点。


    config/secrets.yml添加到版本控制并再次部署。 您可能需要从.gitignore中删除一行,以便您可以提交该文件。

    我有完全相同的问题,结果发现为我的Rails应用程序创建的样板.gitignore Github包括config/secrets.yml


    这对我有用。

    SSH进入生产服务器,cd进入当前目录,运行bundle exec rake secretrake secret,您将得到一个长字符串作为输出,复制该字符串。

    现在运行sudo nano /etc/environment

    粘贴到文件的底部

    1
    2
    export SECRET_KEY_BASE=rake secret
    ruby -e 'p ENV["SECRET_KEY_BASE"]'

    其中rake secret是您刚复制的字符串,将复制的字符串粘贴到rake secret

    重新启动服务器并运行echo $SECRET_KEY_BASE进行测试。


    虽然你可以像其他答案一样使用初始化器,但传统的Rails 4.1+方法是使用config/secrets.yml。 Rails团队引入这个问题的原因超出了这个答案的范围,但是TL; DR是secret_token.rb将配置和代码混为一谈以及存在安全风险,因为令牌被检入源控制历史记录和唯一的系统需要知道生产密钥令牌的是生产基础架构。

    您应该将此文件添加到.gitignore,就像不将config/database.yml添加到源控件一样。

    在他们的Buildpack for Ruby中引用Heroku自己的代码来从DATABASE_URL设置config/database.yml,我最终分配了他们的repo并修改它以从SECRETS_KEY_BASE环境变量创建config/secrets.yml

    由于此功能是在Rails 4.1中引入的,因此我觉得编辑./lib/language_pack/rails41.rb并添加此功能是合适的。

    以下是我在公司创建的修改后的buildpack的片段:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    class LanguagePack::Rails41 < LanguagePack::Rails4

      # ...

      def compile
        instrument"rails41.compile" do
          super
          allow_git do
            create_secrets_yml
          end
        end
      end

      # ...

      # writes ERB based secrets.yml for Rails 4.1+
      def create_secrets_yml
        instrument 'ruby.create_secrets_yml' do
          log("create_secrets_yml") do
            return unless File.directory?("config")
            topic("Writing config/secrets.yml to read from SECRET_KEY_BASE")
            File.open("config/secrets.yml","w") do |file|
              file.puts <<-SECRETS_YML
    <%
    raise"No RACK_ENV or RAILS_ENV found" unless ENV["RAILS_ENV"] || ENV["RACK_ENV"]
    %>

    <%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
      secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
              SECRETS_YML
            end
          end
        end
      end

      # ...

    end

    您当然可以扩展此代码以添加其他秘密(例如第三方API密钥等)以从您的环境变量中读取:

    1
    2
    3
    4
    ...
    <%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
      secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
      third_party_api_key: <%= ENV["THIRD_PARTY_API"] %>

    这样,您就可以以非常标准的方式访问此秘密:

    1
    Rails.application.secrets.third_party_api_key

    在重新部署应用程序之前,请务必先设置环境变量:
    Setting SECRET_KEY_BASE in Heroku Dashboard

    然后将您修改后的buildpack(或者您非常欢迎链接到我的)添加到您的Heroku应用程序(请参阅Heroku的文档)并重新部署您的应用程序。

    每次git push到Heroku时,buildpack将自动从环境变量创建config/secrets.yml作为dyno构建过程的一部分。

    编辑:Heroku自己的文档建议创建config/secrets.yml以从环境变量中读取,但这意味着您应该将此文件检入源代码控制。在我的情况下,这不能很好地工作,因为我有开发和测试环境的硬编码秘密,我宁愿不签到。


    您可以将密钥导出为服务器的~/.bashrc~/.bash_profile上的环境变量:

    1
    export SECRET_KEY_BASE ="YOUR_SECRET_KEY"

    然后,您可以获取.bashrc.bash_profile

    1
    2
    source ~/.bashrc
    source ~/.bash_profile

    永远不要提交你的秘密


    我做了什么 :
    在我的生产服务器上,我为Thin创建了一个配置文件(confthin.yml)(我正在使用它)并添加以下信息:

    1
    2
    3
    4
    environment: production
    user: www-data
    group: www-data
    SECRET_KEY_BASE: mysecretkeyproduction

    然后我启动应用程序

    1
    thin start -C /whereeveristhefieonprod/configthin.yml

    像魅力一样工作,然后无需在版本控制上使用密钥

    希望它可以提供帮助,但我相信Unicorn和其他人可以做同样的事情。


    Demi Magus的答案为我工作直到Rails 5。

    在Apache2 / Passenger / Ruby(2.4)/ Rails(5.1.6)上,我不得不放

    1
    export SECRET_KEY_BASE=GENERATED_CODE

    来自Demi Magus的回答在/ etc / apache2 / envvars中,导致/ etc / profile似乎被忽略了。

    资料来源:https://www.phusionpassenger.com/library/indepth/environment_variables.html#apache


    在Nginx / Passenger / Ruby(2.4)/ Rails(5.1.1)上没有其他工作,除了:

    passenger_env_var在服务器块中的/etc/nginx/sites-available/default中。

    资料来源:https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_env_var


    这很好用https://gist.github.com/pablosalgadom/4d75f30517edc6230a67
    对于root用户应该编辑

    1
    $ /etc/profile

    但如果你非root应该把生成代码放在下面

    1
    2
    3
    4
    5
    $ ~/.bash_profile

    $ ~/.bash_login

    $ ~/.profile

    我创建了config/initializers/secret_key.rb文件,我只写了以下代码行:

    1
    Rails.application.config.secret_key_base = ENV["SECRET_KEY_BASE"]

    但我认为@Erik Trautman发布的解决方案更优雅;)

    编辑:
    哦,最后我在Heroku上找到了这个建议:https://devcenter.heroku.com/changelog-items/426 :)

    请享用!


    我有一个我在Rails 4.1应用程序中使用的补丁,让我继续使用遗留密钥生成器(因此与Rails 3的向后会话兼容性),允许secret_key_base为空。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Rails::Application.class_eval do
      # the key_generator will then use ActiveSupport::LegacyKeyGenerator.new(config.secret_token)
      fail"I'm sorry, Dave, there's no :validate_secret_key_config!" unless instance_method(:validate_secret_key_config!)
      def validate_secret_key_config! #:nodoc:
        config.secret_token = secrets.secret_token
        if config.secret_token.blank?
          raise"Missing `secret_token` for '#{Rails.env}' environment, set this value in `config/secrets.yml`"
        end
      end
    end

    我已经重新格式化了补丁,将其作为Pull请求提交给Rails


    我使用https://github.com/github/gitignore/blob/master/Rails.gitignore中的.gitignore文件后遇到了同样的问题

    在我评论.gitignore文件中的以下行之后,一切都很顺利。

    1
    2
    config/initializers/secret_token.rb
    config/secrets.yml