« July 20, 2010 | Main | October 2, 2011 »

September 25, 2011

Installing Redmine on Mac OS X 10.6: The Correct Way

Yes, it’s a rather pretentious title, considering that it’s my first time succeeding at installing a Rails application, and no, I don’t care. It was a pain in the ass so I need to document how I did it, and it might help other people, so if it really bothers you, read it as ‘the correct way for me’.

Redmine (1.2.1 of 2011-07-11 as of this writing) is pretty touchy about its requirements: gems (and Ruby and RubyGems as well) cannot be too old, some cannot be too recent, and one (i18n) even cannot be anything other than the specified version (0.4.2).

The Redmine installation page says it requires:

  • Ruby 1.8.6 or 1.8.7, not 1.9;
  • RubyGems 1.3.7 or higher, but not 1.5.0 and not 1.7.0 or higher, because Rails 2.3.11 fails with it;
  • Rails 2.3.11 (then later tells you that 2.3.14 works as well);
  • Rack 1.1.1;
  • Rake 0.8.7 (not 0.9.x because it’s not supported by Rails);
  • i18n 0.4.2 (the current version 0.6.0 will give you an error that 0.4.2 cannot be found).

Moreover, Redmine comes with Rails 2.3.11 bundled in the vendor directory, and will use it unless you remove it from there and change the version you want in config/environment.rb. This is neatly documented on the install page with a very thorough explanation: “read config/environment.rb first”. Just changing the version won’t help: if Redmine finds rails in its vendor directory, it will use that one.

The reality of Redmine requirements is a bit different. Rake 0.9.x is supported by Rails 2.3.14 (it installs 0.9.2 as part of its dependencies), but RubyGems 1.7.0 or higher still isn’t. So to minimise the number of obsolete and buggy software that I run and the fuss that ensues, I am going to use Rails 2.3.14.

Using RVM

Ruby Version Manager, or RVM, allows you to use a different version of Ruby and a different set of gems for different projects, without installing said gems system-wide. It is similar to Python’s virtualenv. In my opinion, it is absolutely vital to use it right from the start. You never know what other software you might want to install later, software that might have requirements as tricky as Redmine’s, yet different in the actual versions.

RVM can be found at http://beginrescueend.com/ and is installed thusly (it apparently requires git, which is kind of a bummer if you don’t use it. But you should give it a try, it’s awesome once you start grokking it):

$ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

Then add the following to your .bash_profile or .zshrc (obviously you want to switch to zsh and use oh-my-zsh, because they’re awesome too) as the install script will tell you (personalised with your $HOME path):

# This loads RVM into a shell session.
[[ -s "/Users/olivier/.rvm/scripts/rvm" ]] && source "/Users/olivier/.rvm/scripts/rvm"

Next we need to install the latest pre-1.9 Ruby to use with RVM. RVM will build it from source, but it doesn’t take too long (if you find it does, just head over to 9gag.com. We can list the available Ruby versions, and then install the one we want, namely 1.8.7 (that will result in ruby-1.8.7-p352):

$ rvm list known

# MRI Rubies
[ruby-]1.8.6[-p420]
[ruby-]1.8.6-head
[ruby-]1.8.7[-p352]
[ruby-]1.8.7-head
[ruby-]1.9.1-p378
[ruby-]1.9.1[-p431]
[ruby-]1.9.1-head
[ruby-]1.9.2-p180
[ruby-]1.9.2[-p290]
[ruby-]1.9.2-head
[ruby-]1.9.3[-preview1]
[ruby-]1.9.3-head
ruby-head
...

$ rvm install 1.8.7
...
$ rvm use 1.8.7

Once done, we will create a gemset for Redmine, where RubyGems will install the gems we need in the versions we need, without interfering with the system installation.

$ rvm gemset create redmine
'redmine' gemset created (/Users/olivier/.rvm/gems/ruby-1.8.7-p352@redmine).
$ rvm gemset use redmine

Notes:

  1. The Ruby version and gemset in use are tied to the shell session, so you have to switch every time you start a new shell. It can be done in one step:

    $ rvm use 1.8.7@redmine
    Using /Users/olivier/.rvm/gems/ruby-1.8.7-p352 with gemset redmine
    
  2. The current environment can be queried with rvm-prompt:

    $ rvm-prompt        
    ruby-1.8.7-p352@redmine
    
  3. You can switch back to the system Ruby with:

    $ rvm use system
    Now using system ruby.
    
  4. You do not need sudo to install gems in an RVN gemset, because all the files are contained in your home directory.

  5. Rake commands while using a gemset should be prefixed by rvm:

    $ rvm rake blah blah
    

Installing gems

First of all, let us speed up gem installs 10x, as suggested by The Budding Rubbyist. Add the following to your ~/.gemrc file, creating it if needed:

gem: --no-ri --no-rdoc

That will omit installing the documentation (that we will never read as we’re only interested in using Ruby software, not developing some) when installing gems, a step that is inexplicably very lengthy as it usually takes longer than the “Building native extensions. This could take a while…” step of some gems.

Next, make sure we are using the Ruby and gemset we created earlier:

$ rvm use 1.8.7@redmine

Then install Rails 2.3.14 and i18n 0.4.2 (Rails installs i18n 0.6.0, but remember, Redmine wouldn’t see this one if we forced it into its thick skull with a [we]brick):

gem install rails -v=2.3.14
gem install i18n -v=0.4.2

Note: To figure out that it was Rails 2.3.14 that I wanted, I listed all the versions available and picked the latest 2.3.x:

$ gem query  --all --remote -n '^rails$'

*** REMOTE GEMS ***

rails (3.1.0, 3.0.10, 3.0.9, 3.0.8, 3.0.7, 3.0.6, 3.0.5, 3.0.4, 3.0.3, 3.0.2, 3.0.1, 3.0.0, 2.3.14, 2.3.12, 2.3.11, 2.3.10, 2.3.9, 2.3.8, 2.3.7, 2.3.6, 2.3.5, 2.3.4, 2.3.3, 2.3.2, 2.2.3, 2.2.2, 2.1.2, 2.1.1, 2.1.0, 2.0.5, 2.0.4, 2.0.2, 2.0.1, 2.0.0, 1.2.6, 1.2.5, 1.2.4, 1.2.3, 1.2.2, 1.2.1, 1.2.0, 1.1.6, 1.1.5, 1.1.4, 1.1.3, 1.1.2, 1.1.1, 1.1.0, 1.0.0, 0.14.4, 0.14.3, 0.14.2, 0.14.1, 0.13.1, 0.13.0, 0.12.1, 0.12.0, 0.11.1, 0.11.0, 0.10.1, 0.10.0, 0.9.5, 0.9.4.1, 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.0, 0.8.5, 0.8.0)

The list command is simpler, but it will list everything that starts with rails, which is a bit of a bother:

$ gem list --all --remote rails

*** REMOTE GEMS ***

rails (3.1.0, 3.0.10, 3.0.9, 3.0.8, 3.0.7, 3.0.6, 3.0.5, 3.0.4, 3.0.3, 3.0.2, 3.0.1, 3.0.0, 2.3.14, 2.3.12, 2.3.11, 2.3.10, 2.3.9, 2.3.8, 2.3.7, 2.3.6, 2.3.5, 2.3.4, 2.3.3, 2.3.2, 2.2.3, 2.2.2, 2.1.2, 2.1.1, 2.1.0, 2.0.5, 2.0.4, 2.0.2, 2.0.1, 2.0.0, 1.2.6, 1.2.5, 1.2.4, 1.2.3, 1.2.2, 1.2.1, 1.2.0, 1.1.6, 1.1.5, 1.1.4, 1.1.3, 1.1.2, 1.1.1, 1.1.0, 1.0.0, 0.14.4, 0.14.3, 0.14.2, 0.14.1, 0.13.1, 0.13.0, 0.12.1, 0.12.0, 0.11.1, 0.11.0, 0.10.1, 0.10.0, 0.9.5, 0.9.4.1, 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.0, 0.8.5, 0.8.0)
rails-3-settings (0.1.1)
rails-action-args (0.1.1, 0.1.0)
rails-admin (0.0.0)
rails-and-solid (0.9.1, 0.9.0)
...

I wanted to use SQLite (I couldn’t make the mysql gem build against Zend Server’s MySQL, and I don’t care), so I installed the sqlite3 gem:

gem install sqlite3

We also need to downgrade RubyGems from the latest version (1.8.10 as of writing) to a version that is at least 1.3.7 but not 1.5.0 and not 1.7.0 or later. The version we want can be determined the same way as for Rails, by querying the rubygems-update gem:

$ gem list --all --remote  rubygems-update

*** REMOTE GEMS ***

rubygems-update (1.8.10, 1.8.9, 1.8.8, 1.8.7, 1.8.6, 1.8.5, 1.8.4, 1.8.3, 1.8.2, 1.8.1, 1.8.0, 1.7.2, 1.7.1, 1.7.0, 1.6.2, 1.6.1, 1.6.0, 1.5.3, 1.5.2, 1.5.0, 1.4.2, 1.4.1, 1.4.0, 1.3.7, 1.3.6, 1.3.5, 1.3.4, 1.3.3, 1.3.2, 1.3.1, 1.3.0, 1.2.0, 1.1.1, 1.1.0, 1.0.1, 1.0.0, 0.9.5, 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.0, 0.8.11, 0.8.10, 0.8.8, 0.8.6, 0.8.5, 0.8.4, 0.8.3)

So we want 1.6.2:

$ gem update --system 1.6.2
...
$ gem -v
1.6.2

Note that some older version of the gem command, like the 1.3.7 recommended by Redmine, do not support specifying the version in the gem update --system command. In that case, you would need to get the most recent version and then downgrade it:

$ gem update --system
$ gem update --system 1.6.2

Now let’s proceed to installing Redmine.

Installing Redmine

Download the latest stable release (1.2.1 of 2011-07-11 as of this writing) and unpack it.

We need to disable the built-in Rails 2.3.11 and tell Redmine to use our 2.3.14 version. In config/environment.rb, change these lines:

# Specifies gem version of Rails to use when vendor/rails is not present
RAILS_GEM_VERSION = '2.3.11' unless defined? RAILS_GEM_VERSION

to:

# Specifies gem version of Rails to use when vendor/rails is not present
RAILS_GEM_VERSION = '2.3.14' unless defined? RAILS_GEM_VERSION

Next, move rails out of the vendor directory. If you don’t, Redmine will use the old version no matter what the above line says. I do this:

mv vendor/rails vendor.rails.disabled

By the way, it’s the “read config/environment.rb first” bit in the requirements list and the “when vendor/rails is not present” in the comment above that tell us that we must remove rails from the vendor directory. As I said, a very thorough explanation.

Next, proceed with installation. With SQLite, database.yml looks like this:

production:
  adapter: sqlite3
  database: db/redmine.db

development:
  adapter: sqlite3
  database: db/redmine.db

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: sqlite3
  database: db/redmine_test.db

Note: The following commands for me were littered with deprecation warnings like this one:

rake/rdoctask is deprecated.  Use rdoc/task instead (in RDoc 2.4.2+)
Please install RDoc 2.4.2+ to generate documentation.
WARNING: 'task :t, arg, :needs => [deps]' is deprecated.  Please use 'task :t, [args] => [deps]' instead.
    at redmine-1.2.1/lib/tasks/email.rake:170

As far as I know they don’t matter, apart from the fact that they render it quite difficult to determine whether the task succeeded or not.

Generate a session store secret (don’t forget to rvm rake instead of just rake):

rvm rake generate_session_store

Create the database structure:

RAILS_ENV=production rvm rake db:migrate

Insert default configuration data in database:

RAILS_ENV=production rvm rake redmine:load_default_data

Then test your installation:

ruby script/server webrick -e production

or

ruby script/server -p 3000 webrick -e production

It takes a little while to start. The first two lines appear quite quickly and let you check that Redmine is running the correct Rails version:

=> Booting WEBrick
=> Rails 2.3.14 application starting on http://0.0.0.0:3000

Then the server is ready when you see this:

=> Call with -d to detach
=> Ctrl-C to shutdown server
[2011-09-25 14:28:09] INFO  WEBrick 1.3.1
[2011-09-25 14:28:09] INFO  ruby 1.8.7 (2011-06-30) [i686-darwin10.8.0]
[2011-09-25 14:28:09] INFO  WEBrick::HTTPServer#start: pid=39670 port=3000

Running Redmine under Unicorn

Disclaimer: I have no idea if using Unicorn to run Redmine is a good idea. I just know that WEBrick is not for production and that Passenger is an Apache module, and I’d rather not bother with it if I can avoid it. After all, we reached thus far without need admin privileges.

I found the instruction at Install Redmine on Ubuntu Server from the Redmine HowTo’s list, except the part about the RVM wrapper that comes from Brandon Tilley.

Install Unicorn, still under RVM:

$ gem install unicorn

Create a wrapper for unicorn_rails. The wrapper will run unicorn_rails with the correct Ruby version and gemset:

$ rvm wrapper ruby-1.8.7-p352@redmine redmine unicorn_rails

This creates a redmine_unicorn_rails command that uses the ruby-1.8.7-p352@redmine environment.

Create the unicorn configuration file unicorn.conf, for example in Redmine’s config directory:

# /var/www/redmine/config/unicorn.conf

# Number of CPU Cores
worker_processes 2

# Same Redmine User
user "redmine", "redmine"
working_directory "/var/www/redmine"

# Listen on Both UNIX and TCP Sockets for Testing
listen "/var/www/redmine/tmp/sockets/.sock", :backlog => 64
listen 8080, :tcp_nopush => true

# Default Timeout
timeout 30

# Pid/Logging Config
pid "/var/www/redmine/tmp/pids/unicorn.pid"
stderr_path "/var/www/redmine/log/unicorn.stderr.log"
stdout_path "/var/www/redmine/log/unicorn.stdout.log"

# Preload Rails App for Performance
preload_app true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

This assumes that you unpacked redmine in /var/www/redmine and that you have a redmine user belonging to a redmine group. If needed, change all occurrences of /var/www/redmine to where you installed Redmine and user "redmine", "redmine" to the user and group you want Redmine to run as. For testing, I used my user account, but it’s certainly not recommended:

user "olivier", "staff"

Then start unicorn using the wrapper, which means we don’t need to enter the RVM environment. This should come in handy if you use launchd or another service system to launch Redmine:

$ sudo -u redmine redmine_unicorn_rails -c /var/www/redmine/config/unicorn.conf -D -E production

If like me you used your own user account for testing purposes, then you don’t need the sudo part:

$ redmine_unicorn_rails -c /var/www/redmine/config/unicorn.conf -D -E production

From the config file, Unicorn runs on port 8080. If you have an Apache web site on port 80 and would like Redmine to appear under a given prefix, and have mod_proxy enabled, then you can probably use a proxy rewrite rule to achieve this.

To stop Unicorn, kill the unicorn_rails master process.

Conclusion

That’s it for today, I hope this helps. As I already mentioned, I am new to Rails applications, so I probably made mistakes. Don’t hesitate to point them out in the comments, I’ll try and update this post accordingly. I might also add something about using launchd to run Redmine under Unicorn and mod_proxy to integrate with an existing web site.

Do not meddle in the affairs of Coding Ninjas, for they are subtle and quick to anger.