Setting environment variables in ubuntu production server and Rails - ruby-on-rails

I have the following code in my controller:
def email_signup
email_address = params[:email_address]
response = RestClient.post("https://api:#{ENV['MAILGUN_API_KEY']}" \
"#api.mailgun.net/v3/lists/#{ENV['MAILGUN_ALIAS']}/members",
:subscribed => true,
:address => email_address)
redirect_to jobs_url, success: "Thanks for Signing Up!"
rescue RestClient::BadRequest => e
redirect_to jobs_url, error: e
end
Works great in dev using dotenv gem. After deploying to the server, I added the new environment variables to /etc/environment and deployed with capistrano again to restart the app and the app is giving me a RestClient::Unauthorized (401 Unauthorized): when I try to call this action which makes me think the env. vars are not set.
From the server console if I cd in to the railsapp/current and run ruby -e 'p ENV["MAILGUN_ALIAS"]' then I can see the variable print correctly.
I have also tried exporting the variables in .bashrc which doesn't change the behavior.
Also, just FYI, I am using RVM on the server to set the ruby version.
What else can I try here?

With Capistrano, have you set your .env in your shared folder?
config/deploy.rb:
set :linked_files, fetch(:linked_files, []).push(
'config/database.yml', 'config/secrets.yml', '.env'
)
Then obviously make sure you have your .env file configured with your secrets in the shared folder on the server that runs your application.

Related

How to store environment variables with Figaro on a non Heroku server?

I have a Rails 5 app, and I'm trying to store my environment variables on a non Heroku server.
Therefore I created a config/application.yml file with my environment variables on the production server.
However, when I try to deploy my Rails app, the deployment fails because the environment variables can't be accessed.
Am I missing something?
This answer is tested with Capistrano 3.6.1
Well, in that case, you would have to make capistrano upload your application.yml (database.yml if its ignored from git).
# in config/deploy.rb
# Default value for :linked_files is []
append :linked_files, 'config/database.yml', 'config/application.yml'
Now write some code to upload the files to the server
# lib/capistrano/tasks/uploader.rake
namespace :upload do
desc 'Upload shared files to the server'
task :yml_files do
on roles(:web) do |host|
fetch(:linked_files).each do |common_file|
upload! common_file, "#{fetch(:deploy_to)}/shared/#{common_file}"
end
end
end
end
Now you need to trigger the above mentioned capistrano task just before a very specific event.
# config/deploy.rb
before 'deploy:check:linked_files', 'upload:yml_files'
This will make sure the necessary environment variables are set before your deployed tries to boot your application in the production server.

Refresh .bashrc with new env variables

I have a production server running our rails app, and we have ENV variables in there, formatted correctly. They show up in rails c but we have an issue getting them to be recognized in the instance of the app.
Running puma, nginx on an ubuntu box.
What needs to be restarted every time we change .bashrc? This is what we do:
1. Edit .bashrc
2. . .bashrc
3. Restart puma
4. Restart nginx
still not recognized..but in rails c, what are we missing?
edit:
Added env variables to /etc/environment based on suggestions from other posts saying that .bashrc is only for specific shell sessions, and this could have an effect. supposedly /etc/environment is available for all users, so this is mine. still having the same issues:
Show up fine in rails c
Show up fine when I echo them in shell
Do not show up in application
export G_DOMAIN=sandboxbaa3b9cca599ff0.mailgun.org
export G_EMAIL=mailgun#sandboxbaa3ba3806d5b499ff0.mailgun.org
export GEL=support#xxxxxx.com
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
edit:
In the app i request G_DOMAIN and G_EMAIL in plain html (this works on development with dotenv, does not work once pushed to production server with ubuntu server) :
ENV TEST<BR>
G_DOMAIN: <%= ENV['G_DOMAIN'] %><br>
G_EMAIL:<%= ENV['G_EMAIL'] %>
However, the following env variables are available to use (in both .bashrc and /etc/environment, same as all variables we displayed above) because our images work fine and upload to s3 with no issue, on production.
production.rb
# Configuration for Amazon S3
:provider => 'AWS',
:aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
edit2: could this be anything with this puma issue?
https://github.com/puma/puma/commit/a0ba9f1c8342c9a66c36f39e99aeaabf830b741c
I was having a problem like this, also. For me, this only happens when I add a new environment variable.
Through this post and after some more googling, I've come to understand that the restart command for Puma (via the gem capistrano-puma) might not see new environment variables because the process forks itself when restarting rather than killing itself and being started again (this is a part of keeping the servers responsive during a deploy).
The linked post suggests using a YAML file that's only stored on your production server (read: NOT in source control) rather than rely on your deploy user's environment variables. This is how you can achieve it:
Insert this code in your Rails app's config/application.rb file:
config.before_configuration do
env_file = File.join(Rails.root, 'config', 'local_env.yml')
YAML.load(File.open(env_file)).each do |key, value|
ENV[key.to_s] = value
end if File.exists?(env_file)
end
Add this code to your Capistrano deploy script (config/deploy.rb)
desc "Link shared files"
task :symlink_config_files do
on roles(:app) do
symlinks = {
"#{shared_path}/config/local_env.yml" => "#{release_path}/config/local_env.yml"
}
execute symlinks.map{|from, to| "ln -nfs #{from} #{to}"}.join(" && ")
end
end
before 'deploy:assets:precompile', :symlink_config_files
Profit! With the code from 1, your Rails application will load any keys you define in your server's Capistrano directory's ./shared/config/local_env.yml file into the ENV hash, and this will happen before the other config files like secrets.yml or database.yml are loaded. The code in 2 makes sure that the file in ./shared/config/ on your server is symlinked to current/config/ (where the code in 1 expects it to be) on every deploy.
Example local_env.yml:
SECRET_API_KEY_DONT_TELL: 12345abc6789
OTHER_SECRET_SHH: hello
Example secrets.yml:
production:
secret_api_key: <%= ENV["SECRET_API_KEY_DONT_TELL"] %>
other_secret: <%= ENV["OTHER_SECRET_SHH"] %>
This will guarantee that your environment variables are found, by not really using environment variables. Seems like a workaround, but basically we're just using the ENV object as a convenient global variable.
(the capistrano syntax might be a bit old, but what is here works for me in Rails 5... but I did have to update a couple things from the linked post to get it to work for me & I'm new to using capistrano. Edits welcome)

Heroku S3 Env variables

I'm trying to use carrierwave to upload images to S3. It works locally but when I go to deploy to heroku I get the following error:
ArgumentError: Missing required arguments: aws_access_key_id, aws_secret_
access_key
The keys are definitely set because I can see them when I run heroku:config
I've searched every answer I could find on stack and I searched through every answer on the first 3 pages of Google. None of them have worked.
I know the uploading works so it's not the code that's a problem. What settings or variables do I have to set to make this work?
Please help, I can't move forward with my app until this is done (so I can deploy to heroku again without it being stopped because of this error.)
Some info:
Environment Variables
You've got a problem with the calling of your environment variables in
Heroku. ENV vars are basically variables stored in the OS /
environment, which means you've got to set them for each environment
you attempt to your deploy application
heroku config should should the ENV vars you've set. If you don't see ENV['AWS_ACCESS_KEY'] etc, it means you've not set them correctly, which as explained is as simple as calling the command heroku config:add YOUR_ENV_VAR=VAR
Figaro
I wanted to recommend using Figaro for this
This is a gem which basically stores local ENV vars in config/application.yml. This allows you to store ENV variables locally; but more importantly, allows you to sync them with Heroku using this command:
rake figaro:heroku
This will set your env vars on Heroku, allowing you to use them with Carrierwave as recommended in the other answers
It sounds like you have set the ENV variables on Heroku, but you need to hook those up to CarrierWave.
In config/initializers/fog.rb
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => Rails.configuration.s3_access_key_id,
:aws_secret_access_key => Rails.configuration.s3_secret_access_key,
}
end
In your environments/<environment>.rb file
Rails.application.configure do
config.s3_access_key_id = ENV['S3_ACCESS_KEY_ID']
config.s3_secret_access_key = ENV['S3_SECRET_ACCESS_KEY']
end
This sets your Rails config to the ENV variables on Heroku which makes them available as Rails.configuration.<key>

Environment variable in Rails console and Pow

I can't access env variables in the Rails console, while in the application they work.
In .powenv I have export SENDGRID_PASSWORD="123"
In config/initializers/mail.rb there is:
ActionMailer::Base.smtp_settings = {
:password => ENV['SENDGRID_PASSWORD']
}
So in the console when I type UserMailer.welcome_mail.deliver there is an error 'ArgumentError: SMTP-AUTH requested but missing secret phrase'. However from the application it sends the mail successfully.
How can I make the env variables available in the console?
try
. .powenv
then
rails c
(dot is a command to run script on current environment)
Your Rails console isn't able to access the environment variable because Pow passes information from the .powenv or .powrc file into Rails ... Rails doesn't read those files on its own.
In other words, you're setting the ENV['SENDGRID_PASSWORD'] variable in the .powenv file, but that file is not being touched when you start the Rails console.
You'll need to set up a before_filter in your Application Controller that sets the ENV['SENDGRID_PASSWORD'] (or come up with another, similar, way of reading in the .powenv file from within that before_filter in your Rails app).
For posterity, you can add something like this to either your environment.rb, development.rb, or an initializer (config/initializers/pow.rb) depending on what load order you want:
# Load pow environment variables into development and test environments
if File.exist?(".powenv")
IO.foreach('.powenv') do |line|
next if !line.include?('export') || line.blank?
key, value = line.gsub('export','').split('=',2)
ENV[key.strip] = value.delete('"\'').strip
end
end

Why are Moonshine/Capistrano having SFTP trouble during deploy:setup?

I'm having trouble setting up a new server using Moonshine and Capistrano. It seems to get started pretty well, installs a bunch of Ubuntu packages, compiles REE, installs some gems, but then it fails to upload a file via SFTP with this output:
* executing `moonshine:setup_directories'
* executing "mkdir /tmp/moonshine"
servers: ["myserver.tld"]
[myserver.tld] executing command
command finished
servers: ["myserver.tld"]
** sftp upload /Users/arussell/Sites/mysite/config/moonshine/production.yml -> /tmp/moonshine/production.yml
/Users/arussell/.rvm/gems/ree-1.8.7-2011.03/gems/capistrano-2.5.19/lib/capistrano/transfer.rb:196:in `normalize': undefined method `pos' for #<Pathname:0x10f3a6988> (NoMethodError)
from /Users/arussell/.rvm/gems/ree-1.8.7-2011.03/gems/capistrano-2.5.19/lib/capistrano/transfer.rb:104:in `prepare_transfers'
Googling that error isn't really turning much up, all I can figure out is that capistrano/transfer.rb is expecting something other than a PathName object on line 196, but I'm not sure what it's expecting, nor am I sure why it's being fed a PathName object.
Edit: Here is my deploy.rb:
set :stages, %w(staging production dev)
set :default_stage, "staging"
require 'capistrano/ext/multistage' rescue "YOU NEED TO INSTALL THE capistrano-ext GEM"
require 'fileutils'
if ENV['branch']
set :branch, ENV['branch']
end
set :deploy_via, :remote_cache
before "deploy:restart", "deploy:delete_cache"
namespace(:deploy) do
desc "delete cache"
task :delete_cache do
run "rm -rf /usr/local/shared/cache/"
end
task :null, :roles => :app do
run "date"
end
end
require './config/boot'
... and my deploy/production.rb:
server "myserver.tld", :app, :web, :db, :primary => true
set :rails_env, 'production'
Edit 2: I tried using SCP instead of SFTP, but that didn't go any better. I added this to my deploy/production.rb:
upload "local", "remote", :via => :scp
download "remote", "local", :via => :scp
and got this error instead while trying to deploy:
upload via scp failed on myserver.tld: SCP did not finish successfully () (SCP did not finish successfully ())
I can't figure that error out either. It appears the version of Capistrano your using is fairly outdated by a year plus. I would update the version your using to a more recent release, and try again.
If that still doesn't resolve your problem it would help if you provided sanitized copy of your deploy.rb configuration.
Turns out that this was due to Moonshine not being able to handle the presence of deploy-stage-specific files (eg config/moonshine/production.yml) during cap production deploy:setup.
Here's how I got around it:
Remove config/moonshine/production.yml (replace production with whatever your deploy stage is called)
Run cap production deploy:setup
Put config/moonshine/production.yml back
Then run cap production deploy

Resources