Setup Guide: Rails Stack with Passenger, RVM, Bundler, Apache, and MySQL on Ubuntu

Here’s how I like to setup a Rails stack on Ubuntu 10.4. This recipe makes use of Apache as the webserver with Passenger to serve Rails, MySQL as the database, RVM (installed system-wide) to manage Ruby (I select Ruby 1.9.2 as the default these days), and the latest Rails, which is 3.0.3 as of this morning, and Bundler for installing gems. It also makes a system user for you to use, and a deploy user for deployments with Capistrano.

This isn’t a script, so don’t try a cut-n-paste here. You’ll want to enter the commands one by one. It won’t take long, but things seem to go better if you have a caffeinated beverage on hand when you start out.

This also isn’t a comprehensive guide as much as it is a quick-start recipe for people who are already competent on the command line. There’s more you can and should do afterwards regarding security, backups, log rotation, and more, but those things are outside the scope of this article.

And as usual, follow these steps at your own risk. I accept no liability if you break your server, website, or anything else.

echo -e "\n111.222.333.444  server.example.com  server\n" >> /etc/hosts
echo "servername" > /etc/hostname

Replace 111.222.333.444 with your IP, and servername.example.com and servername with the name of your server in the lines above.

hostname -F /etc/hostname
dpkg-reconfigure tzdata
apt-get -y update
apt-get -y upgrade
apt-get -y install apache2 apache2-prefork-dev autoconf bison build-essential curl git-core imagemagick libapr1-dev libaprutil1-dev libcurl4-openssl-dev libid3-3.8.3-dev libmysqlclient16 libmysqlclient16-dev libreadline6 libreadline6-dev libsqlite3-0 libsqlite3-dev libssl-dev libxml2-dev libxslt-dev libyaml-dev mysql-client mysql-common mysql-server openssl sqlite3 zlib1g zlib1g-dev
bash < <( curl -L http://bit.ly/rvm-install-system-wide )
source /usr/local/lib/rvm
rvm install ruby-1.9.2
rvm --default use 1.9.2

If you want to use a different ruby, you’d just replace your version in the lines above where you see ruby-1.9.2 and 1.9.2.

echo "[[ -s \"/usr/local/lib/rvm\" ]] && source \"/usr/local/lib/rvm\"" > /etc/profile.d/rvm.sh
chmod +x /etc/profile.d/rvm.sh
gem install fastthread bundler capistrano sqlite3-ruby mysql rails passenger
passenger-install-apache2-module
echo "LoadModule passenger_module /usr/local/rvm/gems/ruby-1.9.2-p136/gems/passenger-3.0.2/ext/apache2/mod_passenger.so" > /etc/apache2/mods-available/passenger.load
echo -e "PassengerRoot /usr/local/rvm/gems/ruby-1.9.2-p136/gems/passenger-3.0.2\nPassengerRuby /usr/local/rvm/wrappers/ruby-1.9.2-p136/ruby" > /etc/apache2/mods-available/passenger.conf
a2enmod rewrite
a2enmod passenger
mysql -u root -p
create database mydatabase;
grant all privileges on mydatabase.* to 'myusername'@'localhost' identified by 'myprecious' with grant option; flush privileges;
exit

Replace mydatabase with the name of the database, myusername with the name of an app-specific username, and pick a password other than myprecious.

adduser somebody
adduser deploy
adduser somebody sudo
adduser somebody rvm
adduser deploy rvm

These lines create two users, one for you with sudo access privs (change somebody in the lines above to your own name), and a deploy user. It also adds them to the necessary groups.

su - somebody
ssh-keygen -t rsa
exit
su - deploy
ssh-keygen -t rsa
exit

This makes the ssh keys you’ll want to add to your Git repository (or GitHub) as account and deploy keys, respectively. Again, replace somebody with your username.

Then, on your local machine (if you’re running a *NIX-style OS) you’ll want to scp your local ssh keys to the new accounts on the server.

scp -p ~/.ssh/id_rsa.pub somebody@111.222.333.444:.ssh/authorized_keys
scp -p ~/.ssh/id_rsa.pub deploy@111.222.333.444:.ssh/authorized_keys
scp deploy@111.222.333.444:.ssh/id_rsa.pub ./deploy-key

Be sure to replace 111.222.333.444 with the IP address of the server.

Test your ability to ssh to the server with the following line:

ssh 111.222.333.444

You should be logged in without having to enter a password.

If it worked, back on the server, secure things up by editing /etc/ssh/sshd_config.

sudo vi /etc/ssh/sshd_config

Find the following two lines (they’re not adjacent to each other) and change them as follows:

PermitRootLogin no
PasswordAuthentication no

Save the file and quit vi, then restart the SSH server:

sudo /etc/init.d/ssh restart

Now, setup a basic Rails site with Apache and Passenger, changing example.com to your domain.

sudo mkdir -p /var/www/sites/example.com
sudo chown deploy.deploy /var/www/sites/example.com
sudo cat > /etc/apache2/sites-available/example.com <<EOF
<VirtualHost *:80>
    ServerName example.com
    DocumentRoot "/var/www/sites/example.com/current/public"
    ErrorLog "/var/log/apache2/example.com-error_log"
    CustomLog "/var/log/apache2/example.com-access_log" common
    <Directory "/var/www/sites/example.com/current/public">
        Options All
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
    RewriteEngine On
    # Remove the www
    RewriteCond %{HTTP_HOST} ^www.example.com$ [NC]
    RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
</VirtualHost>
EOF
sudo a2ensite example.com
sudo a2dissite default
su - deploy
mkdir -p /var/www/sites/example.com/shared/config/
cat > /var/www/sites/example.com/shared/config/database.yml <<EOF
production:
    adapter: mysql2
    encoding: utf8
    reconnect: false
    database: mydatabase
    pool: 5
    username: myusername
    password: myprecious
    socket: /var/run/mysqld/mysqld.sock
EOF
exit
sudo /etc/init.d/apache2 restart

Be sure to replace mydatabase with the name of the database you created earlier, myusername with the username you setup, and myprecious for the password you used.

Then, back on your local machine (assuming you’ve added the ssh keys to your Git repository correctly), you should be able to deploy your app.

If you want to have Capistrano automatically install your app’s gems for you, add these lines at the top of your app’s config/deploy.rb:

$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
require 'rvm/capistrano'
require 'bundler/capistrano'

Then, when you deploy, your gems will be setup for you.

A first-time deploy like this:

cap deploy:setup
cap deploy

If you don’t want to auto-run bundler on deploy, you’ll need to do it manually on the server (as the deploy user) like this:

su - deploy
cd /var/www/sites/example.com/current
bundle install

Enjoy your new server and app.

More articles in the Archive →