Jens Krämer

Deploying Redmine with Capistrano

 |  capistrano, devops, ruby, rails, redmine

This is part two of my guide on how to self-administer Redmine for the long run. The first part was about Managing your own version of Redmine with Git.

With your own Redmine repository in place, it’s time to…

Automate Your Deployment

Really. Don’t try to do it the oldfashioned way and copy things around manually.

Automating your deployment is a one time investment that pays back in saved time and trouble everytime you want (or have) to upgrade your Redmine. The goal is to make deployments so easy that even the tiniest bug fix or enhancement can be deployed instantly because it’s fast, reliable and can be triggered with a single command.

Wether you’re the local server admin or a Python developer tasked with setting up Redmine in your organization, I’m asking you to learn how “the Pros”, that is, the people that develop and run Rails apps for a living, deploy and run their stuff. Over the years a lot of bright people spent a lot of time developing a toolchain that, once set up, makes zero downtime deployments of Rails apps with a single keystroke a breeze. It’s all there, you just have to use it. And it’s quite possible you’ll learn a thing or two that are useful outside the context of Redmine.

Capistrano

Capistrano, the Remote multi-server automation tool, is the weapon of choice when it comes to deployment automation. It’s implemented in Ruby but not restricted to deploying Ruby or Rails applications. Anything that can be done via SSH, you can automate with Capistrano. And you can do it on any number of servers in parallel. Capistrano is for deployment what Chef is for server provisioning (but much easier to use).

I’ll give you just a very short intro mentioning some Redmine specifics, be sure to read on over at capistranorb.com. The Readme is a good starting point.

Capistrano Installation

In your local/x.y-stable Redmine branch, create a file named Gemfile.local. That’s going to hold any gems local to your private Redmine installation.

group :development do
  # uncomment if you're using modern (and secure!) ed25519 ssh keys
  # gem 'net-ssh', '4.0.0.alpha2'
  gem 'capistrano', '~> 3.4.0'
  gem 'capistrano-rails', require: false
end

After creating this file, run bundle install and add/commit Gemfile.local as well as the resulting Gemfile.lock.

Now run bundle exec cap install to set up Capistrano. This will give you a few new files - config/deploy.rb and two files in config/deploy/, which correspond to the two default deployment targets or stages. If you have separate Redmine installation for testing purposes like trying out new plugins, that would be your staging target, while the live (productive) stage is production. The basic idea is that everything common goes into deploy.rb, and the things that set the different stages apart go into their corresponding files in config/deploy. Most often you’ll only specify the target host there, and maybe set a different git branch or deployment user name.

A Basic Capistrano Setup for Redmine

Here’s what a minimal Capistrano config might look like:

# config valid only for current version of Capistrano
lock '3.4.0'

set :application, 'redmine'

set :scm, :git
set :repo_url, 'git@code.yourcompany.com:redmine.git'

# Target directory in the server.
# Should exist and the user account you're using for deployment should
# have write access.
set :deploy_to, '/srv/webapps/redmine'

set :pty, true
set :log_level, :info

# Linked files are expected to exist below /srv/webapps/redmine/shared and will be
# symlinked into the deployed # code. Create them either manually or through an
# automation tool like chef. The reason for doing so is to not keep database
# credentials and server secrets in your git repository.
set :linked_files, fetch(:linked_files, []).push('config/database.yml',
                                                 'config/secrets.yml')

# Directories with contents you want to keep across deployments are declared here. 
# Most important is files where Redmine stores any uploaded files.
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp',
                                               'vendor/bundle', 'files')

# keep the last 5 deployed versions on the server.
# Useful in case you have to revert to an older version.
set :keep_releases, 5

namespace :deploy do

  # Declares a task to be executed once the new code is on the server.
  after :updated, :plugin_assets do
    on roles(:app) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          # Copy over plugin assets
          execute :rake, 'redmine:plugins:assets'
          # Run plugin migrations
          execute :rake, 'redmine:plugins:migrate'
        end
      end
    end
  end

  # This will run after the deployment finished and is used to reload
  # the application. You most probably have to change that depending on
  # your server setup.
  after :published, :restart do
    on roles(:app) do
      sudo "/etc/init.d/unicorn reload redmine"
    end
  end

  # cleans up old versions on the server (keeping the number of releases
  # configured above)
  after :finished, 'deploy:cleanup'
end

The only things left to configure are which server you’re going to deploy to, the user Capistrano should use to log in on that server, and the branch to deploy:

set :branch, 'local/3.2-stable'
server 'redmine.yourcompany.com', user: 'deploy', roles: %w{web app db}

If you’re using the same machine for staging and production, just move the deploy_to setting to the stage configuration files so you can set a different directory for each stage. Don’t forget to add and commit Gemfile.local, Gemfile.lock and the Capistrano configuration you just set up - it’s a part of your custom Redmine and should be kept in source control along with it.

If you’re using Git submodules for adding plugins or themes to Redmine, have a look at the Capistrano Git submodule strategy to have them automatically deployed as well.

Update (July 2017): For current versions of Capistrano (3.7+) use the capistrano-git-with-submodules gem instead.

Authentication

Capistrano is based on SSH, and relies on key-based authentication to be set up properly. It is also very convenient if you’re using some sort of SSH Agent and Agent Forwarding so you can use your local key to access the git repository via the deployment server.

Be sure to read the Authentication & Authorisation chapter of the Capistrano docs.

Run It!

With everything in place, it’s time for a your first deployment:

$ bundle exec cap production deploy

If you set up everything correctly, this should deploy Redmine for you. If it fails, this is often due to permission or authentication problems which are usually easy to fix.