Heroku Alchemy deployment

Heroku is a cloud platform as a service. You can start with a free plan and run it for lifetime. In this guide you will learn how to deploy your existing Alchemy Site on Heroku. After finishing this guide you will know:

  • How to prepare your local Alchemy installation for Heroku
  • How to deploy code changes to Heroku

1 Prerequisites

We assume you already have a running Alchemy application on your local machine. In the following steps we call it my-project. Please replace it name with your actual name. All following shell commands need to be executed within your applications folder from the command shell.

We also assume you already have an account on Heroku. Otherwise signup now.

You need the Heroku Toolbelt for your OS installed to get access to the Heroku Command Line utility. Login with the heroku command from your command shell as described in the devcenter.

The last thing we assume is you already have an Amazon AWS account. Otherwise signup now.

2 Amazon (AWS) setup

2.1 Create S3 buckets

Heroku does not provide data storage on its filesystem (beside a small amount for the application code and some temporary data). So we have to store our pictures and attachments outside of Heroku. Amazon S3 comes for the rescue. We need two S3 buckets, one for Alchemy pictures and another for Alchemy attachments.

Please create two S3 buckets now and name them as follows:

  • my-project-alchemy-pictures
  • my-project-alchemy-attachments

Please make sure to save the keys (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) Amazon gives you and keep them safe.

3 Heroku setup

3.1 Create a new application

Create a new Application from your Dashboard.

3.2 Install Memcache add-on

We use Memcache to store and deliver cropped pictures and the page cache. This is important because otherwise page publishing and image cropping will not work accordingly.

Lets add MemCachier to the application.


$ heroku addons:create memcachier:dev

This installs MemCachier with a 25M cache store for free.

3.3 Set environment variables

Run the following commands on your command shell to set some environment variables on your heroku account to provide the S3 key and bucket names. Make sure to replace my-project and your-key with the correct information.


$ heroku config:set AWS_ACCESS_KEY_ID=your-key-id
$ heroku config:set AWS_SECRET_ACCESS_KEY=your-key
$ heroku config:set AWS_PICTURES_DIRECTORY=my-project-pictures
$ heroku config:set AWS_ATTACHMENTS_DIRECTORY=my-project-attachments

4 Code adjustments

4.1 Add gems

We need to add a few gems to the Gemfile of the Application.


gem 'thin'

group :production do
  gem 'pg'
  gem 'rails_12factor'
  gem 'rack-cache', require: 'rack/cache'
  gem "dragonfly-s3_data_store"
  gem 'dalli'
  gem 'kgio'
end

Now bundle the gems


$ bundle install

Heroku uses PostgreSQL. If you want to use a different database for your development environment you need to define group: "development" for the relevant database adapter gem.

4.2 Use thin webserver instead of webrick

Webrick is not the best choice for running rails applications in production. Lets tell Heroku we want to use thin instead. Create a new file in your applications root directory named Procfile and paste the following line.


web: bundle exec thin start -p $PORT -e $RACK_ENV

4.3 Create initializer

Create a new initializer config/initializers/alchemy_file_storage.rb in your application code to overwrite the information how and where Alchemy pictures and attachments are stored. You can just paste the following code and adjust the region if necessary. Be aware to use the same region as you did when creating the buckets.

We set up the application to use Amazon S3 storage on production while using the filesystem in other environments.


if Rails.env.production?
  require 'dragonfly'
  require 'dragonfly/s3_data_store'

  aws_defaults = {
    access_key_id: Rails.configuration.aws_access_key_id,
    secret_access_key: Rails.configuration.aws_secret_access_key,
    region: 'eu-west-1',
    storage_headers: {'x-amz-acl' => 'public-read'},
    url_scheme: 'https'
  }

  Dragonfly.app(:alchemy_pictures).configure do
    plugin :imagemagick
    datastore :s3,
      { bucket_name: Rails.configuration.aws_pictures_directory }.merge(aws_defaults)
  end

  Dragonfly.app(:alchemy_attachments).configure do
    datastore :s3,
      { bucket_name: Rails.configuration.aws_attachments_directory }.merge(aws_defaults)
  end
end

4.4 Configure rack-cache for production environment


# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like
# NGINX, varnish or squid.
config.action_dispatch.rack_cache = true
# use the Dalli client for its cache-store
config.cache_store = :dalli_store
client = Dalli::Client.new((ENV["MEMCACHIER_SERVERS"] || "").split(","),
                         :username => ENV["MEMCACHIER_USERNAME"],
                         :password => ENV["MEMCACHIER_PASSWORD"],
                         :failover => true,
                         :socket_timeout => 1.5,
                         :socket_failure_delay => 0.2,
                         :value_max_bytes => 10485760)
config.action_dispatch.rack_cache = {
  :metastore    => client,
  :entitystore  => client
}
config.static_cache_control = "public, max-age=311040000"

4.5 Make S3 informations accessible to Rails configuration

Paste the following lines to your config/environments/production.rb inside the configure block. The Rails application gets access to the S3 information provided via environment variables.


config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
config.aws_pictures_directory = ENV['AWS_PICTURES_DIRECTORY']
config.aws_attachments_directory = ENV['AWS_ATTACHMENTS_DIRECTORY']

4.6 Prepare your seeds.rb

In order to populate the remote database with basic information (which is needed for running Alchemy) please paste the following to your db/seeds.rb. You can skip this step if you already have it.


Alchemy::Seeder.seed!

5 Git repository

5.1 Create a new repo

If your application code is already checked-in to a git repository you can skip this. Otherwise initialize a new git repository now.


$ git init

5.2 Make sure you do not store certain files in your git repo

We do not want certain files in git. Please make sure you ignore at least following files/folders in your .gitignore file.


/tmp/*
/log/*
/uploads
/public/assets
/public/pictures
/config/database.yml
.DS_Store
/db/*.sqlite3

5.3 Commit your files to the git repository


$ git add .
$ git commit -am "Initial commit"

Never store any critical informations like database or ssh passwords in your git repository, even if you have a private one.

5.4 Add heroku as a git remote

You need to add heroku as a remote git repository. Each time you push the master branch to heroku the application will be deployed.


$ heroku git:remote -a my-project

6 Deployment

6.1 First deployment

Lets deploy the application to heroku the first time! Its easy as pushing our repository to the heroku git remote.


$ git push heroku master

6.2 Migrate and seed the database

We need to migrate the database and populate it with Alchemy seed data.


$ heroku run rake db:migrate
$ heroku run rake db:seed

6.3 Verify the deployment

Open a browser and enter the domain Heroku gave you. Usually its a subdomain consisting of your project name and the domain herokuapp.com (e.g.: https://my-project.herokuapp.com)

You can always get your domain from the settings on Heroku. E.g.: https://dashboard.heroku.com/apps/my-project/settings (replace my-project with the correct name)

6.4 Deploy the app later on

Each time you want to deploy to Heroku just push your git commits to the heroku remote:


$ git push heroku master