Im trying to set up my app to run in production mode and Ive hit a problem with building the assets folder specifically this line in my Dockerfile:
RUN bundle exec rake RAILS_ENV=production DATABASE_URL=postgresql://user:pass#127.0.0.1/dbname SECRET_TOKEN=dummytoken assets:precompile
The database is just a dummy line. The problem is when it runs the rake it seems to not see the env variables and I get the following errors when it goes to initialize carrierwave.rb
rake aborted!
ArgumentError: Missing required arguments: aws_access_key_id, aws_secret_access_key
/usr/local/bundle/gems/fog-core-1.42.0/lib/fog/core/service.rb:244:in `validate_options'
/usr/local/bundle/gems/fog-core-1.42.0/lib/fog/core/service.rb:268:in `handle_settings'
/usr/local/bundle/gems/fog-core-1.42.0/lib/fog/core/service.rb:98:in `new'
/usr/local/bundle/gems/fog-core-1.42.0/lib/fog/core/services_mixin.rb:16:in `new'
/usr/local/bundle/gems/fog-core-1.42.0/lib/fog/storage.rb:27:in `new'
/usr/local/bundle/gems/carrierwave-0.11.2/lib/carrierwave/uploader/configuration.rb:83:in `eager_load_fog'
/usr/local/bundle/gems/carrierwave-0.11.2/lib/carrierwave/uploader/configuration.rb:96:in `fog_credentials='
/mnt/hgfs/Projects/livingrecipe/config/initializers/carrierwave.rb:3:in `block in <top (required)>'
/usr/local/bundle/gems/carrierwave-0.11.2/lib/carrierwave/uploader/configuration.rb:118:in `configure'
/usr/local/bundle/gems/carrierwave-0.11.2/lib/carrierwave.rb:14:in `configure'
/mnt/hgfs/Projects/livingrecipe/config/initializers/carrierwave.rb:1:in `<top (required)>'
Theres a few more lines to the error but the first line says it all and the ENV variables for the aws_access_key_id and aws_secret_access_key dont seem to load up. If I run this without trying to precompile the assets everything works but I need to precompile the assets to make them visible to nginx
I did find that for a fix I could replace the ENV variables with what they are, this is the code that is having the trouble:
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'AWS', # required
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'], # required
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], # required
region: 'us-west-2' # optional, defaults to 'us-east-1'
}
config.fog_directory = ENV['S3_BUCKET_NAME'] # required
#config.fog_host = 'https://assets.example.com' # optional, defaults to nil
#config.fog_public = false # optional, defaults to true
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
end
So I got it to work with just typing in the keys...but obviously that isnt a good solution long term to have the keys programmed in.
Your question has shifted a bit, so I'm going to address your last sentence:
So I got it to work with just typing in the keys...but obviously that isn't a good solution long term to have the keys programmed in.
If you're sure you want to handle this during your build, as opposed to adding your rake task to your command entry, you can set build args in your docker-compose.yml config file.
# compose.yml
version: '2'
services:
app:
# ...
build:
context: .
args:
# This will make your variables available during the
# "build" phase.
# You can hardcode these values here, or better,
# add them to a .env file, whose contents
# Docker/Compose will make available during the build.
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- DATABASE_URL
- SECRET_TOKEN
environment:
# You should also add these values to your application's
# environment.
# You can hardcode these values here, or better,
# add them to a .env file, whose contents
# Docker/Compose will make available to your running container.
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- DATABASE_URL
- SECRET_TOKEN
You can then declare and use the build args in your Dockerfile:
# Dockerfile
# ...
ARG AWS_ACCESS_KEY_ID
ARG AWS_SECRET_ACCESS_KEY
ARG DATABASE_URL
ARG SECRET_TOKEN
# these values will now be available to your rake task
# in ENV['AWS_ACCESS_KEY_ID'], etc.
RUN bundle exec rake RAILS_ENV=production assets:precompile
Related
I have finished Michael Hartl tutorial and I'm trying to deploy it with https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04. Unfortunately I'm stuck with RAILS_ENV=production rake db:migrate because it's generating following error:
ArgumentError: Missing required arguments: aws_access_key_id, aws_secret_access_key
/home/me/simpleapp/config/initializers/carrier_wave.rb:3:in `block in <top (required)>'
/home/me/simpleapp/config/initializers/carrier_wave.rb:2:in `<top (required)>'
/home/me/simpleapp/config/environment.rb:5:in `<top (required)>
'
I have even copied those files 1:1 and still this error persists. Any idea how could I solve it? I really am tired with trying to fix it with different solutions from web.
Thanks
edit: I am adding my carrier_wave file:
if Rails.env.production?
CarrierWave.configure do |config|
config.fog_credentials = {
# Configuration for Amazon S3
:provider => 'AWS',
:aws_access_key_id => ENV['S3_ACCESS_KEY'],
:aws_secret_access_key => ENV['S3_SECRET_KEY']
}
config.fog_directory = ENV['S3_BUCKET']
end
end
The root issue is that Carrier Wave is expecting your AWS environment variables to be populated but they are not set in your production environment.
I would recommend you look at something like the dotenv gem which can find here. Environment variable housekeeping in multiple environments can be a real pain so it helps to have a tool to facilitate. Dotenv (and others like it) provides more of a turn key approach to this.
Note that the recently introduced secrets.yml for Rails secret management is a nice step in the right direction, but still requires a bit of code/know how to utilize.
In any event, be very careful about how you manage any files with secrets. At a minimum, the file should be in your .gitignore so that you aren't potentially broadcasting your secrets.
My cron job works fine on my local machine after running whenever -w, after deploy to my VPS, I get this error, release 20150415044915 doesn't exist. any idea?
I looked at my crontab -e, the path also looks fine where 20150502114703 is the correct release:
0 1 * * 1 /bin/bash -l -c 'cd /home/hey_production/releases/20150502114703 && bin/rails runner ....
Error Log:
/usr/local/rvm/gems/ruby-2.1.3/gems/bundler-1.7.3/lib/bundler/definition.rb:22:in `build': /home/hey_production/releases/20150415044915/Gemfile not found (Bundler::GemfileNotFound)
from /usr/local/rvm/gems/ruby-2.1.3/gems/bundler-1.7.3/lib/bundler.rb:154:in `definition'
from /usr/local/rvm/gems/ruby-2.1.3/gems/bundler-1.7.3/lib/bundler.rb:117:in `setup'
from /usr/local/rvm/gems/ruby-2.1.3/gems/bundler-1.7.3/lib/bundler/setup.rb:17:in `<top (required)>'
from /usr/local/rvm/rubies/ruby-2.1.3/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:135:in `require'
from /usr/local/rvm/rubies/ruby-2.1.3/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:135:in `rescue in require'
from /usr/local/rvm/rubies/ruby-2.1.3/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:144:in `require'
from bin/rails:14:in `<main>'
Basically the environment variable is missing that tells the cron where to look for a Gemfile. so you need to add that variable in your environment at the time when cron tries to run this.
You can do that in Your schedule.rb:
env BUNDLE_GEMFILE, ENV["/home/hey_production/current/Gemfile"]
or directly inside crontab file with the command crontab -e(before the cron entries):
BUNDLE_GEMFILE="/home/hey_production/current/Gemfile"
Hope it helps.
EDIT
Forgot the symbol above in schedule.rb
The line in schedule.rb should be like this.
env :BUNDLE_GEMFILE, ENV["/#{path}/Gemfile"]
or
env :BUNDLE_GEMFILE, ENV["/home/hey_production/current/Gemfile"]
As a follow up on previous answer, set the env variable in whenever inside schedule.rb before the schedule blocks like:
def production?
#environment == 'production'
end
set :output, {:error => '/home/current/log/cron_error.log', :standard => '/home/current/log/cron.log'}
every 2.hour, roles: [:utility] do
runner "/home/current/lib/cron_jobs/launch_pending_emails.rb"
end
and inside your deploy.rb environment specific file ie: staging.rb set the env:
set :whenever_roles, [:utility]
set :whenever_environment, defer { stage }
set(:whenever_command) { "STAGE=#{stage} bundle exec whenever" }
require 'whenever/capistrano'
So I'm deploying to a Ubuntu droplet hosted on DigitalOcean a Rails 4 application running on Apache and Phusion Passenger. After deployment I've been getting 500s as a result of Rails production not finding the secret_key_base token for production. However, if I run an echo $SECRET_KEY_BASE it returns the rake secret generated by my deploy.rb.
The deploy.rb task to set that up is:
namespace :deploy do
task :start do ; end
task :stop do ; end
desc "Setup ENV variables"
task :env_vars do
on "root#xxx.xxx.xxx.xx" do
execute "export SECRET_KEY_BASE=#{`bundle exec rake secret`}"
end
end
end
before "deploy", "deploy:env_vars"
However, Rails is still not picking it up. I even ssh'd into my server and in rails console checked and ENV["SECRET_KEY_BASE"] returns the correct secret token.
I thought using Capistrano's :default_env would work, but that only seems to set up environmental variables for the deploy task, but not actually on the server. Is there any easy way to solve this solution? My fallback is to just place the secret within secrets.yml since the repo is private, but I rather not do that.
There is a gem for exactly this task:
https://github.com/capistrano-plugins/capistrano-secrets-yml
Install
Add this to Gemfile:
group :development do
gem 'capistrano', '~> 3.2.1'
gem 'capistrano-secrets-yml', '~> 1.0.0'
end
And then:
$ bundle install
Setup and usage
make sure your local config/secrets.yml is not git tracked. It should be on the disk, but gitignored.
populate production secrets in local config/secrets.yml:
production:
secret_key_base: d6ced...
add to Capfile:
require 'capistrano/secrets_yml'
create secrets.yml file on the remote server by executing this task:
$ bundle exec cap production setup
You can now proceed with other deployment tasks.
You can create a file in your server called application.yml in shared/config.
Choose any one of solution from bellow
Following code in deploy.rb will automatically symlink your application.yml
set :linked_files, %w{config/application.yml}
Or
Then symlink this application.yml with your current/config/application.yml with a simple capistrano task.
Rather than exporting env variables in deploy.rb, use dotenv to load environment variables from .env[.<staging>] into ENV when rails booting.
Follow these steps:
Add this line to the top of your Gemfile:
gem 'dotenv-rails'
Put .env.production file into the linked_file in deploy/production.rb:
set :linked_files, fetch(:linked_files, []).push('.env.production')
On the remote host, add the .env.production file in shared folder which contains this line:
SECRET_KEY_BASE=<Your secret>
Give up on environment vars and just simply read a file. Do this in secrets.yml.
production:
secret_key_base: <%= File.read('/home/me/SECRET_KEY_BASE').strip %>
Then make the secret file.
$ rake secret > ~/SECRET_KEY_BASE
Before settling on this solution I tried exporting the secret from my .bash_profile, .profile, and .bashrc (top and bottom). I also tried PermitUserEnvironment and .ssh/environment. I have no idea how an environment variable gets from "the environment" into a capistrano deployment. I ran ssh example.com printenv and saw my vars. I logged in and saw my vars. But puma started with capistrano... it always has it's own environment.
Here's my carrierwave config file:
CarrierWave.configure do |config|
config.storage = :aws
config.aws_bucket = ENV.fetch('S3_BUCKET_NAME')
config.aws_acl = :public_read
config.asset_host = 'http://example.com'
config.aws_credentials = {
access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY')
}
end
The server won't start and returns:
14:53:23 web.1 | /home/tom/paul/config/initializers/carrierwave.rb:9:in `fetch': key not found: "AWS_ACCESS_KEY_ID" (KeyError)
I entered the keys like this in the command line:
export AWS_ACCESS_KEY_ID="demo12345"
both with and without the quote marks
the command
env
displays them OK
I would use the Gem 'Figaro' to help manage environment variables. Very easy to set-up and manage.
1) Add to your Gemfile and bundle:
gem 'figaro', '1.0'
2) run 'figaro install'
figaro install
3) Open up the generated file: config/application.yml and add the variables:
SAMPLE_PASSWORD: exAmplePa$$
SAMPLE_USERNAME: myspecialusername
4) Go back into your initializer file and change your variable too:
user_name: ENV['SAMPLE_USERNAME'],
password: ENV['SAMPLE_PASSWORD'],
You should be good to go!
You should be changed/edit in config/environments/development.rb
as it:
S3_BUCKET_NAME= ******your bucket name ****
AWS_ACCESS_KEY_ID= ******your acess key_id***
AWS_SECRET_ACCESS_KEY= ********* your secret key ***
AWS_REGION= ******* your region ***
Long story short, I decided to use VM for development in addition to my local machine.
So when I pulled my source code inside that VM and ran rspec I received following output:
action#rails:~/workspace(master)$ rspec
/home/action/.rvm/gems/ruby-2.0.0-p451/gems/devise-3.2.3/lib/devise/rails/routes.rb:481:in `raise_no_secret_key': Devise.secret_key was not set. Please add the following to your Devise initializer: (RuntimeError)
config.secret_key = '...'
I've added the key, but now I have following errors in specs:
2) Password pages user views his passwords
Failure/Error: sign_in user
RuntimeError:
Missing `secret_key_base` for 'test' environment, set this value in `config/secrets.yml`
# ./spec/support/login_macros.rb:3:in `sign_in'
# ./spec/features/account_pages_spec.rb:7:in `block (2 levels) in <top (required)>'
What should be inside that file?
I just installed rails 4.1 and created a new project. The following is the default generated content of config/secrets.yml:
# Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.
development:
secret_key_base: 83aa0c7d6e2ed4574099514eb64bc3896fb8a71a344935fbd54705e0dd65adb897bc062fe477d03395a4d65675c833ba73ed340166be3874bfc01f43d6076385
test:
secret_key_base: 513fb7657945b56098db290394bf23f5e11463c473fb228719428a30fd34b8b899dff3f6173c32d7e6bc028dc3276f15dcba11b684d27983d8203fb5634ce8ae
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
You can generate a new key using rake secret then updating the value of config.secret_key.
$ rake secret
Use the output of the above command as the value for config.secret_key usually placed in config/initializers/devise.rb for devise. Restart rails server if you are using that as well.