This article was published on April 19th 2015 and takes about 4 minutes to read.
Use it with caution — it is probably still valid, but it has not been updated for over a year.
What you should know before setting environment variables for your Rails application
Setting environment variables for your Rails applications can be tricky at times. Learn about 3 gotchas and my preferred way to define them in a production environment.
Table of contents
Some time ago, Rails introduced the file config/secrets.yml
to store your application's secret variables. When you create a new Rails application, this file defines a variable called secret_key_base
which your application uses to sign cookies.
When you take a look at this file, you will notice that each environment (development, test and production) has its own secret_key_base
. What's important is that while for development and test environment the variable's value is set directly in this file, Rails expects to read this value from an environment variable when running in production.
Setting values from environment variables is an elegant way to prevent sensible data (like API tokens or passwords) from being stored in your application's code repository.
But there are gotchas you have to be aware of:
1. Your app fails to start without environment variables
A default Rails application needs at least SECRET_KEY_BASE
and RAILS_ENV
set in order to start.
While RAILS_ENV
nearly always falls back to a default value (making your app start in development mode in the worst case), an undefined SECRET_KEY_BASE
simply results in your application serving a blank page. On further investigation, you will find messages complaining about missing secret_key_base
in your application server's log file.
The preferred way to set environment variables on CentOS systems is to define them in a file under /etc/profile.d
. Scripts in this directory are run for each new login shell so you can use the export
command to define environment variables:
export RAILS_ENV=production
export SECRET_KEY_BASE=abc
export API_TOKEN=def
2. Your app fails to start on a reboot
When you start your application server using an init script, you may experience this behaviour:
Having defined your application's environment variables in a file under /etc/profile.d
, your application starts without problems when you manually run its init script but fails to do so when your server reboots.
The problem here is that these files are only executed for login shells. When your init script runs in the course of the boot process, these files are not executed and therefore no environment variables are set.
You can remedy that by sourcing the according file inside your init script with . /etc/profile.d/myapp.sh
.
3. Everything configured correctly, nothing works
If you have configured everything correctly and still get strange messages about a missing SECRET_KEY_BASE
in your application server's log, the you may suffer from a really mean problem:
I had problems with my internet connection a few weeks ago resulting in massive package loss (sometimes up to 50%). While installing/updating my application's gems, bundle install
sometimes had to be run several times because Bundler could not resolve the IP address of rubygems.org every now and then and thus halted the installation process.
Even though at some point all gems were installed, some of them obviously were corrupted resulting in my application not being able to read the secrets.yml
file properly (and thus setting the secret_key_base
variable).
Re-installing all my application's gem dependencies solved this issue.
A sidenote: A more elegant way to define environment variables
I am using rbenv on my production machines to manage Ruby versions and I recently discovered rbenv-vars, which is since my preferred way to manage my applications' enviroment variables.
rbenv-vars is an rbenv plugin. To install it, simply clone git@github.com:sstephenson/rbenv-vars.git
to your rbenv installation's plugin
directory.
Once installed, it will look for a file called .rbenv-vars
in your current working directory or any of its parent directories. To set environment variables, just define them as key/value pairs:
RAILS_ENV=production
SECRET_KEY_BASE=abc
API_KEY=def
These variables will be set whenever a new Ruby process is spawned. To set global default values, define them in ~/.rbenv/vars
.
The advantages:
- Since setting of environment variables is now tied directly to your Ruby processes, it just works (no matter if your app is launched during the boot process or manually).
- You could launch one of your apps with
RAILS_ENV
set todevelopment
(maybe for debugging purposes) without affecting the others — this would be quite hard to accomplish with global environment variables defined in files under/etc/profile.d
. - It helps to keep all your applications' configuration under one dedicated directory (instead of spreading files all over your system).
However, one small gotcha remains:
Since these environment variables are set when a new Ruby process spawns, you will not be able to see them using *nix commands like env
or echo $RAILS_ENV
. If you want to know which variables are set, use the command rbenv vars
.
When using RVM, take a look at the .ruby-env
file, which seems to offer the same functionality.
Get in the loop
Join my email list to get new articles delivered straight to your inbox and discounts on my products.
No spam — guaranteed.
Got it, thanks a lot!
Please check your emails for the confirmation request I just sent you. Once you clicked the link therein, you will no longer see these signup forms.