188

I created a Rails application, using Rails 4.1, from scratch and I am facing a strange problem that I am not able to solve.

Every time I try to deploy my application on Heroku I get an error 500:

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

The secret.yml file contains the following configuration:

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

On Heroku I configured the "SECRET_KEY_BASE" environment variable with the result of the rake secret command. If I launch heroku config, I can see the variable with the correct name and value.

Why am I still getting this error?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Paolo Laurenti
  • 2,714
  • 2
  • 16
  • 18
  • 1
    I'm having the exact same problem and would love to know why this is happening, too. If I figure out why, I'll post back with my solution. – danielricecodes Apr 21 '14 at 20:52
  • Is your config file called `secret.yml` or `secrets.yml`? – James Apr 21 '14 at 21:53
  • 2
    I configured again the .gitignore file with the one generated by rails and now everything works fine – Paolo Laurenti Apr 22 '14 at 09:27
  • We also had this issue when we upgraded to Rails 4. In our case, it was because we had a custom environment name, and that wasn't reflected in secrets.yml. I just had to add a line to the file with the non-standard name, commit, and re-deploy. – whognu Mar 08 '16 at 15:27
  • For future readers: this answer is probably the easiest and most accurate: stackoverflow.com/a/26541742/4880924 – BenKoshy Apr 11 '18 at 00:12

15 Answers15

230

I had the same problem and solved it by creating an environment variable to be loaded every time I logged in to the production server, and made a mini-guide of the steps to configure it:

I was using Rails 4.1 with Unicorn v4.8.2 and when I tried to deploy my application it didn't start properly and in the unicorn.log file I found this error message:

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

After some research I found out that Rails 4.1 changed the way to manage the secret_key, so if you read the secrets.yml file located at exampleRailsProject/config/secrets.yml you'll find something like this:

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

This means that Rails recommends you to use an environment variable for the secret_key_base in your production server. In order to solve this error you should follow these steps to create an environment variable for Linux (in my case Ubuntu) in your production server:

  1. In the terminal of your production server execute:

    $ RAILS_ENV=production rake secret
    

    This returns a large string with letters and numbers. Copy that, which we will refer to that code as GENERATED_CODE.

  2. Login to your server

    • If you login as the root user, find this file and edit it:

      $ vi /etc/profile
      

      Go to the bottom of the file using Shift+G (capital "G") in vi.

      Write your environment variable with the GENERATED_CODE, pressing i to insert in vi. Be sure to be in a new line at the end of the file:

      $ export SECRET_KEY_BASE=GENERATED_CODE
      

      Save the changes and close the file using Esc and then ":x" and Enter for save and exit in vi.

    • But if you login as normal user, let's call it "example_user" for this gist, you will need to find one of these other files:

      $ vi ~/.bash_profile
      $ vi ~/.bash_login
      $ vi ~/.profile
      

      These files are in order of importance, which means that if you have the first file, then you wouldn't need to edit the others. If you found these two files in your directory ~/.bash_profile and ~/.profile you only will have to write in the first one ~/.bash_profile, because Linux will read only this one and the other will be ignored.

      Then we go to the bottom of the file using Shift+G again and write the environment variable with our GENERATED_CODE using i again, and be sure add a new line at the end of the file:

      $ export SECRET_KEY_BASE=GENERATED_CODE
      

      Having written the code, save the changes and close the file using Esc again and ":x" and Enter to save and exit.

  3. You can verify that our environment variable is properly set in Linux with this command:

    $ printenv | grep SECRET_KEY_BASE
    

    or with:

    $ echo $SECRET_KEY_BASE
    

    When you execute this command, if everything went ok, it will show you the GENERATED_CODE from before. Finally with all the configuration done you should be able to deploy without problems your Rails application with Unicorn or some other tool.

When you close your shell and login again to the production server you will have this environment variable set and ready to use it.

And that's it! I hope this mini-guide helps you solve this error.

Disclaimer: I'm not a Linux or Rails guru, so if you find something wrong or any error I will be glad to fix it.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Demi Magus
  • 3,377
  • 3
  • 17
  • 23
  • 12
    It seems, that Rails does't sees environment variable SECRET_KEY_BASE. printenv shows it, rails c production also displays it, if I inspect ENV. But, i has no effect, when I restarting Unicorn. The only way, that works now, is pasting it directly to secrets.yml – AntonAL Nov 17 '14 at 20:37
  • 1
    This worked for me. Thank you for your full explanation. I just learned that there are gem that exist for managing an app's environment variables. 'Dotenv' is one and 'foreman' for heroku. While it was education to fix the error manually this way, maybe using one of those gems will streamline the process? – Nick Res Apr 01 '15 at 22:52
  • I'm glad that my answer was helpful, thanks for the gem options @ninja08, they definitively make the process easier, mainly for those who use capistrano or other incremental tool to manage the server :) – Demi Magus Apr 02 '15 at 05:23
  • Following Demi Magus's excellent instructions, I did something like this: cd /var/www/rails; rvm use ext-rbx-2.5.2@rails; SKB_FILE=/var/www/.secret_key_base; echo "export SECRET_KEY_BASE=$(RAILS_ENV=production rake secret)" > $SKB_FILE; . $SKB_FILE; echo ". $SKB_FILE" | tee -a ~/.bashrc ~/.bash_profile; chmod o-rwx $SKB_FILE; – David Winiecki Apr 13 '15 at 16:44
  • Nice answer!! I not know why this not is solved for me, i create question http://stackoverflow.com/questions/33117318/missing-secret-token-and-secret-key-base-for-production-environment – Adriano Resende Oct 14 '15 at 14:22
  • you can use figaro gem https://github.com/laserlemon/figaro to handle environment variables within your rails app. – Jude Calimbas Nov 21 '15 at 09:51
  • Thanks. I had to remove RAILS_ENV=production in my remote Ubuntu environment and run `bundle exec rake secret`. – B. Bulpett Feb 04 '16 at 23:32
  • I LOVE you so much, this fixed my problem <3 <3 <3 – Riveascore Apr 10 '16 at 03:43
  • I have to log out and then login in order to see anything in `echo $SECRET_KEY_BASE` after modifying `/etc/profile` – Eric Luo Jun 29 '16 at 21:21
  • Note that `echo $SECRET_KEY_BASE` can show a value and still not actually be available to the ruby process. `printenv | grep SECRET_KEY_BASE` is what you need to check. The first will still have results if it's only a local value and not exported. If need to load and export a file, you need to do what's here (this is for bash) http://stackoverflow.com/a/30969768/1053377 No, `. .env` or `source .env` will not export them for the child process by default. – Patrick McGuire Dec 06 '16 at 23:46
  • After implementing this step the server stops responding to requests, even curl requests from the server itself. Tried several times and every time after the key is added the puma server stops responding to requests, though it shows as running. –  May 09 '17 at 14:53
  • One note: After you edit the /etc/profile and one of the 3 other profiles, I had to reboot my terminal for it to appear for either `printenv | grep SECRET_KEY_BASE` or `echo $SECRET_KEY_BASE`. – Hayden Holligan Jun 14 '17 at 17:49
  • For future readers: The answer below is 100% easier and basically does the same thing: https://stackoverflow.com/a/26541742/4880924 – BenKoshy Apr 11 '18 at 00:12
95

I'm going to assume that you do not have your secrets.yml checked into source control (ie. it's in the .gitignore file). Even if this isn't your situation, it's what many other people viewing this question have done because they have their code exposed on Github and don't want their secret key floating around.

If it's not in source control, Heroku doesn't know about it. So Rails is looking for Rails.application.secrets.secret_key_base and it hasn't been set because Rails sets it by checking the secrets.yml file which doesn't exist. The simple workaround is to go into your config/environments/production.rb file and add the following line:

Rails.application.configure do
    ...
    config.secret_key_base = ENV["SECRET_KEY_BASE"]
    ...
end

This tells your application to set the secret key using the environment variable instead of looking for it in secrets.yml. It would have saved me a lot of time to know this up front.

Erik Trautman
  • 5,883
  • 2
  • 27
  • 35
  • 16
    This is the best answer. `Figaro` and `heroku_secrets` don't do anything unless Rails knows that `SECRET_KEY_BASE` lives in `ENV`. I've been struggling with this thinking that if the config var existed on Heroku, Rails would pick it up just by virtue of it existing, but now it seems blindingly obvious that Rails would need to know where to look. I've been wondering how I can have code on Github without having to worry about the secret key base thing; now I know. – flanger001 Jan 17 '15 at 21:12
  • 1
    Agreed, I think the secrets.yml is superfluous with great gems like Figaro. – Joe May 02 '15 at 19:11
  • 2
    Seems like the best option if you use github and heroku for your project. – flexus Dec 05 '15 at 08:56
  • 1
    What's wrong with committing your secrets.yml with `production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>`. Won't that also mean the actual secret key is not exposed. Is there risk to exposing dev and test keys in committed secrets.yml if it is all just seed and test data? – Jay Killeen Apr 29 '16 at 01:47
  • This works even in Rails 6.0.2, when there is no secrets.yml any more. – Ken Tsoi Apr 22 '20 at 04:20
51

Add config/secrets.yml to version control and deploy again. You might need to remove a line from .gitignore so that you can commit the file.

I had this exact same issue and it just turned out that the boilerplate .gitignore Github created for my Rails application included config/secrets.yml.

danielricecodes
  • 3,446
  • 21
  • 23
  • should this be the new default for the gitignore? I just figure the Current version should be assumed and previous versions' adjustments described in the gitignore. – max Jun 09 '14 at 23:52
  • As long as you never commit production configuration information to your version control you're good. Use your own judgement. AFAIK, the boilerplate `config/secrets.yml` is safe. – danielricecodes Jun 20 '14 at 18:41
  • 145
    config/secrets.yml should NEVER be in the repo you can do.yml.sample and fill it in with fake data but for security, never do .yml in repos – user3379926 Jul 07 '14 at 19:20
  • 9
    @user3379926, within the context of a Rails app on Heroku, you can't pick and choose which files are included in version control and which are not. Rails 4.1 expects the secret configuration to exist otherwise the application will not run. If you have a way to resolve the issue posed in the Question above without resorting to committing the secrets.yml file in Git, please help improve this thread by providing that advice. – danielricecodes Jul 08 '14 at 14:51
  • 10
    @danielricecodes you can manually set the value in an initializer. Something like `Rails.application.config.secret_key_base = ENV["SECRET_KEY_BASE"]` would work and remove the error without adding `secrets.yml` to source. – joshhepworth Dec 11 '14 at 21:44
  • 11
    @user3379926: When I generate a new Rails application with `rails new` (producing, in this case, a Gemfile whose `rails` gem has the version `4.2.4`), the file `config/secrets.yml` is generated. It includes pregenerated secret keys for the development and test environments, and reads the secretkey for the production environment from an environment variable: `secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>`. Seems to me that it's perfectly safe, and indeed useful, to keep this `secrets.yml` file in version control, provided one never actually defines the secret key there. – Teemu Leisti Aug 27 '15 at 02:46
  • user3379926 mentioned, you should never check in your secrets.yml into your git repo, for future stackoverflow users consider changing this as the accepted answer, as it is not safe or accepted practice. – jasonleonhard Mar 08 '16 at 17:34
  • 3
    @jasonleonhard why? if you're reading the secret key from env vars anyway, what's the big deal? there's no secrets being exposed. – horseyguy Sep 15 '16 at 12:45
  • 1
    @user3379926 Tracking secrets.yml isn't a bad thing unless you put your actual secret values in it. Below Demi Magus shows a way to do this safely by using `<%= ENV["SECRET_KEY_BASE"] %>` – doub1ejack Nov 20 '16 at 20:48
13

This worked for me.

SSH into your production server and cd into your current directory, run bundle exec rake secret or rake secret, you will get a long string as an output, copy that string.

Now run sudo nano /etc/environment.

Paste at the bottom of the file

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

Where rake secret is the string you just copied, paste that copied string in place of rake secret.

Restart the server and test by running echo $SECRET_KEY_BASE.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
sumitsv21
  • 302
  • 3
  • 7
3

While you can use initializers like the other answers, the conventional Rails 4.1+ way is to use the config/secrets.yml. The reason for the Rails team to introduce this is beyond the scope of this answer but the TL;DR is that secret_token.rb conflates configuration and code as well as being a security risk since the token is checked into source control history and the only system that needs to know the production secret token is the production infrastructure.

You should add this file to .gitignore much like you wouldn't add config/database.yml to source control either.

Referencing Heroku's own code for setting up config/database.yml from DATABASE_URL in their Buildpack for Ruby, I ended up forking their repo and modified it to create config/secrets.yml from SECRETS_KEY_BASE environment variable.

Since this feature was introduced in Rails 4.1, I felt it was appropriate to edit ./lib/language_pack/rails41.rb and add this functionality.

The following is the snippet from the modified buildpack I created at my company:

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

You can of course extend this code to add other secrets (e.g. third party API keys, etc.) to be read off of your environment variable:

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

This way, you can access this secret in a very standard way:

Rails.application.secrets.third_party_api_key

Before redeploying your app, be sure to set your environment variable first: Setting SECRET_KEY_BASE in Heroku Dashboard

Then add your modified buildpack (or you're more than welcome to link to mine) to your Heroku app (see Heroku's documentation) and redeploy your app.

The buildpack will automatically create your config/secrets.yml from your environment variable as part of the dyno build process every time you git push to Heroku.

EDIT: Heroku's own documentation suggests creating config/secrets.yml to read from the environment variable but this implies you should check this file into source control. In my case, this doesn't work well since I have hardcoded secrets for development and testing environments that I'd rather not check in.

stackunderflow
  • 546
  • 3
  • 7
  • While a great solution the .dotenv and .foreman gems solve this problem: "I have hardcoded secrets for development and testing environments" - so using those gems means you do not need the buildpack as you can use ENV_VAR in your secrets file for dev and test also – rmcsharry Nov 03 '18 at 09:35
  • Note that environment variables are logged by most infrastructure, which means unencrypted environment variables will be in plain text in the logs. I do not use Heroku for my Rails apps, so have no recommendation for it, but with AWS we pull encrypted values from Parameter Store during build from inside the build container and unencrypt them to populate these kinds of secure assets. – Daniel Nalbach Dec 21 '19 at 23:10
2

You can export the secret keys to as environment variables on the ~/.bashrc or ~/.bash_profile of your server:

export SECRET_KEY_BASE = "YOUR_SECRET_KEY"

And then, you can source your .bashrc or .bash_profile:

source ~/.bashrc 
source ~/.bash_profile

Never commit your secrets.yml

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
alessandrocb
  • 677
  • 8
  • 21
2

For rails6, I was facing the same problem as I was missing the following files. Once I added them the issue was resolved:

1. config/master.key
2. config/credentials.yml.enc

Make sure you have these files!

kometen
  • 6,536
  • 6
  • 41
  • 51
Tushar H
  • 755
  • 11
  • 29
  • You should not version your master.key file, since that contains the key to decrypt your credentials encrypted file – damuz91 Mar 13 '23 at 21:22
0

What I did : On my production server, I create a config file (confthin.yml) for Thin (I'm using it) and add the following information :

environment: production
user: www-data
group: www-data
SECRET_KEY_BASE: mysecretkeyproduction

I then launch the app with

thin start -C /whereeveristhefieonprod/configthin.yml

Work like a charm and then no need to have the secret key on version control

Hope it could help, but I'm sure the same thing could be done with Unicorn and others.

  • 1
    can you explain why/how this is working? The question was for heroku. Is thin an alternative, or is it compatible with heroku? – ahnbizcad Jul 29 '14 at 00:23
-1

I have a patch that I've used in a Rails 4.1 app to let me continue using the legacy key generator (and hence backwards session compatibility with Rails 3), by allowing the secret_key_base to be blank.

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

I've since reformatted the patch are submitted it to Rails as a Pull Request

BF4
  • 1,076
  • 7
  • 23
-1

I've created config/initializers/secret_key.rb file and I wrote only following line of code:

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

But I think that solution posted by @Erik Trautman is more elegant ;)

Edit: Oh, and finally I found this advice on Heroku: https://devcenter.heroku.com/changelog-items/426 :)

Enjoy!

Community
  • 1
  • 1
fadehelix
  • 201
  • 2
  • 14
-1

this is works good https://gist.github.com/pablosalgadom/4d75f30517edc6230a67 for root user should edit

$ /etc/profile

but if you non root should put the generate code in the following

$ ~/.bash_profile

$ ~/.bash_login

$ ~/.profile
Jamie Eltringham
  • 810
  • 3
  • 16
  • 25
-1

On Nginx/Passenger/Ruby (2.4)/Rails (5.1.1) nothing else worked except:

passenger_env_var in /etc/nginx/sites-available/default in the server block.

Source: https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_env_var

Kasperi
  • 853
  • 7
  • 17
-1

Demi Magus answer worked for me until Rails 5.

On Apache2/Passenger/Ruby (2.4)/Rails (5.1.6), I had to put

export SECRET_KEY_BASE=GENERATED_CODE

from Demi Magus answer in /etc/apache2/envvars, cause /etc/profile seems to be ignored.

Source: https://www.phusionpassenger.com/library/indepth/environment_variables.html#apache

Florent L.
  • 403
  • 4
  • 10
-2

In my case, the problem was that config/master.key was not in version control, and I had created the project on a different computer.

The default .gitignore that Rails creates excludes this file. Since it's impossible to deploy without having this file, it needs to be in version control, in order to be able to deploy from any team member's computer.

Solution: remove the config/master.key line from .gitignore, commit the file from the computer where the project was created, and now you can git pull on the other computer and deploy from it.

People are saying not to commit some of these files to version control, without offering an alternative solution. As long as you're not working on an open source project, I see no reason not to commit everything that's required to run the project, including credentials.

Andrew Koster
  • 1,550
  • 1
  • 21
  • 31
  • 5
    Never commit your master key file to git. This is a giant security vulnerability for your app. For open source it's tough, but creating a password vault with your preferred password manager is a better option. – wsizoo Sep 27 '19 at 19:52
  • 1
    You set the `RAILS_MASTER_KEY` environment variable in production. Your answer is very wrong (according to the Rails documentation) and leads to an insecure condition. Please update it or remove it. – Robin Daugherty Sep 09 '21 at 21:45
  • 1
    @RobinDaugherty Please elaborate. What is the "insecure condition", and how should we avoid it? – Andrew Koster Sep 10 '21 at 16:43
  • Just like @wsizoo. Committing the master key to version control is insecure and should not be done. It's in the `.gitignore` file for a very good reason. Share the file via _other means_ for development. Follow 12-factor-app principles and place it in the environment for production. _Especially_ for an open-source project, the master key in production should not be shared with the world. – Robin Daugherty Oct 15 '21 at 15:22
-4

I had the same problem after I used the .gitignore file from https://github.com/github/gitignore/blob/master/Rails.gitignore

Everything worked out fine after I commented the following lines in the .gitignore file.

config/initializers/secret_token.rb
config/secrets.yml
  • 2
    As is repeated everywhere, committing secrets.yml or secret_token.rb to git is NOT recommended. – cofiem Sep 23 '15 at 14:41