Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save davidguttman/1294731 to your computer and use it in GitHub Desktop.
Save davidguttman/1294731 to your computer and use it in GitHub Desktop.
Setup Rails application production environment on Ubuntu

Setup Rails application production environment on Ubuntu

Add deploy user

ssh root@YOURDOMAIN
adduser deploy
visudo # Add deploy ALL=(ALL) ALL

Install necessary libraries

Now, relog as deploy user, update ubuntu packager.

sudo apt-get update

Install following prerequisite libraries for our environment

sudo apt-get install libpcre3-dev build-essential libssl-dev libxml2 libxml2-dev libxslt-dev ncurses-dev

Install image processing libraries

sudo apt-get install imagemagick libmagickcore-dev libmagickwand-dev

Install readline libraries for performing rails console

sudo apt-get install libreadline5-dev libncurses5-dev

Install emacs

sudo apt-get install emacs

Install Git

sudo apt-get install git

Install Nginx

Go to site

cd /opt/
sudo wget http://nginx.org/download/nginx-1.0.2.tar.gz
sudo tar -zxvf nginx-1.0.2.tar.gz
cd nginx-1.0.2
sudo ./configure --prefix=/opt/nginx --user=nginx --group=nginx --with-http_ssl_module
sudo make
sudo make install
su -
adduser --system --no-create-home --disabled-login --disabled-password --group nginx
exit

Install RVM

Go to site

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
exit
ssh deploy@YOURDOMAIN
rvm install 1.9.2
# Remember to add rvm script to bashrc
rvm --default use 1.9.2

If you want readline lib

rvm package install readline
rvm install 1.9.2 --with-readline-dir=$rvm_path/usr

Another way to install readline

apt-get install libreadline5-dev and maybe libncurses5-dev # if not yet
cd ~/.rvm/rubies/ruby-1.8.7-p299
and then to the following:
cd ext/readline
then run the following:
ruby extconf.rb

Update gem system

gem update --system

Something to remember

  • When deploy, need to setup file ownership sudo chown -R deploy:deploy rails_app_folder

  • Remember to install bundler and set up github permission

  • If you are using RVM and capistrano

Add the following to deploy.rb

# Add RVM's lib directory to the load path.
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))

# Load RVM's capistrano plugin.    
require "rvm/capistrano"

set :rvm_ruby_string, '1.9.2'
set :rvm_type, :user  # Don't use system-wide RVM

Secure SSH

Edit sshd_config

Edit /etc/ssh/sshd_config to make ‘Port 22’ to ‘Port [anything higher than 1024]’. Also better to disable root logins (you can always login as local user then su - to perform root level operations)

# Inside /etc/ssh/sshd_config:
Port [anything higher than 1024]
PermitRootLogin no

Then restart the SSH server daemon

/etc/init.d/ssh reload

SSH login (use pwd only the first time)

Generate ssh keys

ssh-keygen -t dsa

Add following line to ~/.bashrc (You’ll need to create ~/.ssh folder on sever if it doesn’t already exist)

function authme {
  ssh $1 ‘cat >>.ssh/authorized_keys’ < ~/.ssh/id_dsa.pub
}

Now reload .bashrc

. ~/.bashrc

Now you can type following to login which will prompt you for the password. (Note that this assumes username is the same locally and on remote)

authme yourhost

Next. you want to enter a new shell with your SSH keys loaded. This will alow you to start a shell and enter your passphrase for your private key only once. Then you will be able to ssh to anywhere your key is placed without enter the passphrase again.

ssh-agent sh -c ‘ssh-add < /dev/null && bash’ 

Now you can ssh without typing passphrase

ssh your_host.com

Setup nginx and thin

Setup site specific nginx config files

Setup site nginx config: put your nginx config file for your site to /usr/local/nginx/conf/vhosts, and have /usr/local/nginx/conf/nginx.conf include them. In the config file for your site, set web server’s document root to [rails_app_location]/current/public (assume using capistrano)

Add include vhosts/*.conf; to end of /usr/local/nginx/conf/nginx.conf

The following resides in /usr/local/nginx/conf/vhosts/rails_app.com.conf

upstream thin {
  server 127.0.0.1:3000;
}

server {
  listen 80;
  server_name rails_app.com www.rails_app.com;

  root /var/www/apps/rails_app.com/current/public;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect false;

    if (-f $request_filename/index.html) {
      rewrite (.*) $1/index.html break;
    }
    if (-f $request_filename.html) {
      rewrite (.*) $1.html break;
    }
    if (!-f $request_filename) {
      proxy_pass http://thin;
      break;
    }
  }

  error_page 500 502 503 504 /50x.html;
  location = /50x.html {
    root html;
  }
}

Run nginx -t to make sure configuration files are valid

Nginx resources

http://nginx.org/en/docs/http/converting_rewrite_rules.html

Setup run level for nginx

Create nginx file as /etc/init.d/nginx, chomd -x it too if needed. This may already be generated, looks like this:

#! /bin/sh
# Author: Ryan Norbauer http://norbauerinc.com
# Modified: Geoffrey Grosenbach http://topfunky.com
# Modified: Clement NEDELCU
# Reproduced with express authorization from its contributors
set -e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="nginx daemon"
NAME=nginx
DAEMON=/usr/local/nginx/sbin/$NAME
SCRIPTNAME=/etc/init.d/$NAME

# If the daemon file is not found, terminate the script.
test -x $DAEMON || exit 0

d_start() {
  $DAEMON || echo -n " already running"
}

d_stop() {
  $DAEMON –s quit || echo -n " not running"
}

d_reload() {
  $DAEMON –s reload || echo -n " could not reload"
}

d_configtest() {
  $DAEMON -t || echo -n " could not test config"
}

case "$1" in
  start)
    echo -n "Starting $DESC: $NAME"
    d_start
    echo "."
  ;;
  stop)
    echo -n "Stopping $DESC: $NAME"
    d_stop
    echo "."
  ;;
  reload)
    echo -n "Reloading $DESC configuration..."
    d_reload
    echo "reloaded."
  ;;
  restart)
    echo -n "Restarting $DESC: $NAME"
    d_stop
    # Sleep for two seconds before starting again, this should give the
    # Nginx daemon some time to perform a graceful stop.
    sleep 2
    d_start
    echo "."
  ;;
  configtest)
    echo -n "Testing $DESC configuration"
    d_configtest
    echo "."
  ;;
  *)
    echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
    exit 3
  ;;
esac

exit 0

Test if thin or nginx are running

ps -ef | grep -i thin
ps -ef | grep -i nginx

# with color
ps aux | egrep ‘(PID|nginx)’

Deploy using capistrano

Github resource

Create rsa pair (from Github tutorial). Do the following at ~

ssh-keygen -t rsa -C “[email protected]

Capistrano steps. always do these locally

capify .

Show all tasks

cap -T

Prepares one or more servers for deployment and setup your database.yml file if needed (for mysql)

cap deploy:setup

The following will copy code to server, symlink current to newest release, and restart

cap deploy

Do migration if need to

cap deploy:migrate

If some case you need to do this on production server

rake db:migrate RAILS_ENV="production"

More tasks

cap deploy:start 
cap deploy:stop

Install Mysql

sudo apt-get install mysql-client mysql-server
sudo apt-get install libmysqlclient-dev # for mysql2 gem
mysql -uroot -p
CREATE USER 'deploy'@'localhost' IDENTIFIED BY 'password'
GRANT ALL ON *.* TO 'deploy'@'localhost'
mysql -uroot -p -e 'CREATE DATABASE project_production DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci'

Install Mongodb

Tutorial from Mongdb official site

cd /opt  
wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-1.8.1.tgz  
tar xzf mongodb-linux-x86_64-1.8.1.tgz  
ln -s mongodb-linux-x86_64-1.8.1 mongodb  
export PATH=/opt/mongodb/bin:$PATH  
mkdir /data  
mkdir /data/db  
mongod  

Setup symlinks

sudo ln -s /usr/local/mongodb-linux-x86_64-1.8.1 /usr/local/mongodb
sudo ln -s /usr/local/mongodb/bin/bsondump /usr/local/bin/bsondump
sudo ln -s /usr/local/mongodb/bin/mongo /usr/local/bin/mongo
sudo ln -s /usr/local/mongodb/bin/mongod /usr/local/bin/mongod
sudo ln -s /usr/local/mongodb/bin/mongodump /usr/local/bin/mongodump
sudo ln -s /usr/local/mongodb/bin/mongoexport /usr/local/bin/mongoexport
sudo ln -s /usr/local/mongodb/bin/mongofiles /usr/local/bin/mongofiles
sudo ln -s /usr/local/mongodb/bin/mongoimport /usr/local/bin/mongoimport
sudo ln -s /usr/local/mongodb/bin/mongorestore /usr/local/bin/mongorestore
sudo ln -s /usr/local/mongodb/bin/mongos /usr/local/bin/mongos
sudo ln -s /usr/local/mongodb/bin/mongosniff /usr/local/bin/mongosniff
sudo ln -s /usr/local/mongodb/bin/mongostat /usr/local/bin/mongostat

The first ln -s above sets up a handy symbolic link between the versioned mongodb folder and its unversioned counterpart. When 10Gen release updates, say version 1.8.2, all you need to do is download, unzip, and link the '1.8.2 mongodb folder' to the unversioned folder and everything should just work.

Setup init script for mongodb

To get an init script working cleanly with this setup, download mine from my Github ‘dotfiles’ repo. Please note – my init script enables journaling and the REST interface (on line 51).

wget https://github.com/ijonas/dotfiles/raw/master/etc/init.d/mongod
sudo mv mongod /etc/init.d/mongod
sudo chmod +x /etc/init.d/mongod

You'll need to add a mongodb user and prep some folders

sudo useradd mongodb
sudo mkdir -p /var/lib/mongodb
sudo mkdir -p /var/log/mongodb
sudo chown mongodb.mongodb /var/lib/mongodb
sudo chown mongodb.mongodb /var/log/mongodb

Add to run-level configuration

Also, you need to activate your MongoDB service's init script by adding it to your system's run-level configuration. That way the service will startup during the boot sequence and stop nicely during the OS' shutdown procedure.

sudo update-rc.d mongod defaults

Lastly to launch MongoDB

/etc/init.d/mongod start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment