Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
DigitalOcean Ubuntu 14.04 x64 + Rails 4 + Nginx + Unicorn + PostgreSQL + Capistrano 3 Setup Instructions

DigitalOcean Ubuntu 14.04 x64 + Rails 4 + Nginx + Unicorn + PostgreSQL + Capistrano 3

Create a Droplet

SSH into Root

$ ssh root@123.123.123.123

Change Root Password

$ passwd

Add Deploy User

$ adduser deployer

Update Sudo Privileges

$ visudo
username ALL=(ALL:ALL) ALL

Configure SSH

$ vi /etc/ssh/sshd_config
Port 22 # Change (1025..65536)
Protocol 2 # Change
PermitRootLogin no  # Change
UseDNS no # Add
AllowUsers deployer # Add

Reload SSH

$ reload ssh

SSH with Deploy User (Don't close root)

$ ssh -p 1026 deployer@123.123.123.123

Install Curl

$ sudo apt-get update
$ sudo apt-get install curl

Install RVM

$ curl -L get.rvm.io | bash -s stable
$ source ~/.rvm/scripts/rvm
$ rvm requirements
$ rvm install 2.2.0
$ rvm use 2.2.0 --default
$ rvm rubygems current

Install PostgreSQL

$ sudo apt-get install postgresql postgresql-server-dev-9.3
$ gem install pg -- --with-pg-config=/usr/bin/pg_config

Create Postgres User

$ sudo -u postgres psql
create user deployer with password 'password';
alter role deployer superuser createrole createdb replication;
create database MYAPP_production owner deployer;

Install GIT

$ sudo apt-get install git-core

Install Bundler

$ gem install bundler

Setup Nginx

$ sudo apt-get install nginx
$ nginx -h
$ cat /etc/init.d/nginx
$ /etc/init.d/nginx -h
$ sudo service nginx start
$ sudo vim /etc/nginx/sites-enabled/default

upstream unicorn {
  server unix:/tmp/unicorn.MYAPP.sock fail_timeout=0;
}

server {
  listen 80 default deferred;
  # server_name example.com;
  root /home/deployer/apps/MYAPP/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  location ~ ^/(robots.txt|sitemap.xml.gz)/ {
    root /home/deployer/apps/MYAPP/current/public;
  }

  try_files $uri/index.html $uri @unicorn;
  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

Add Unicorn

$ vim Gemfile
gem 'unicorn'    

Update Unicorn Config

$ vim config/unicorn/production.rb

root = "/home/deployer/apps/MYAPP/current"
working_directory root

pid "#{root}/tmp/pids/unicorn.pid"

stderr_path "#{root}/log/unicorn.log"
stdout_path "#{root}/log/unicorn.log"

worker_processes Integer(ENV['WEB_CONCURRENCY'])
timeout 30
preload_app true

listen '/tmp/unicorn.spui.sock', backlog: 64

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

# Force the bundler gemfile environment variable to
# reference the capistrano "current" symlink
before_exec do |_|
  ENV['BUNDLE_GEMFILE'] = File.join(root, 'Gemfile')
end

Add Capistrano

$ vim Gemfile

group :development do
  gem 'capistrano-rails'
  gem 'capistrano-rvm'
  gem 'capistrano3-unicorn'
end

Install Capistrano

$ bundle exec cap install

Update Capistrano Capfile

$ vim Capfile

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rvm'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'

# Load custom tasks from `lib/capistrano/tasks' if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

Update Capistrano Deploy Config

$ vim config/deploy.rb

lock '3.3.5'

set :application, 'spui'
set :repo_url, 'git@github.com:MYGITHUB/MYAPP.git'

ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call

set :use_sudo, false
set :bundle_binstubs, nil
set :linked_files, fetch(:linked_files, []).push('config/database.yml')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')

after 'deploy:publishing', 'deploy:restart'

namespace :deploy do
  task :restart do
    invoke 'unicorn:reload'
  end
end

Update Production Deploy Config

$ vim config/deploy/production.rb

set :port, 22
set :user, 'deployer'
set :deploy_via, :remote_cache
set :use_sudo, false

server '123.333.333.333',
  roles: [:web, :app, :db],
  port: fetch(:port),
  user: fetch(:user),
  primary: true

set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"

set :ssh_options, {
  forward_agent: true,
  auth_methods: %w(publickey),
  user: 'deployer',
}

set :rails_env, :production
set :conditionally_migrate, true    

Add SSH Key to DigitalOcean

$ cat ~/.ssh/id_rsa.pub | ssh -p 22 username@123.123.123.123 'cat >> ~/.ssh/authorized_keys'

Say Hi to Github

# follow the steps in this guide if receive permission denied(public key)
# https://help.github.com/articles/error-permission-denied-publickey
$ ssh github@github.com    

Check Deployment (Commit and Push)

$ cap production deploy:check

Deploy

$ cap production deploy

Thanks to James Dullaghan for his help.

Hi,
Thank you for this really!

I have an existing rails application and I want to deploy it.

Now the tutorial is specifically for
DigitalOcean Ubuntu 14.04 x64 + Rails 4 + Nginx + Unicorn + PostgreSQL + Capistrano 3

But I usesd
DigitalOcean Ubuntu 14.10 x34( my droplet image, the option I chose) + Rails 4 + Nginx + Unicorn + Mysql + Capistrano 3

Now I fixed all the errors that came up through the way and made sure that nginx is starting and the command "cap production deploy" works fine and gives no errors. I restarted nginx and then I went to my droplet's ip address and refreshed the page but nothing happens. Not even a spinner. I have no Idea what to do or how to debug this issue.

Can you help me please? Do you think it is a unicorn related problem?

As a side note my local machine is (ubuntu 14.04x64) but when I created the droplet I chose the image to be (ubuntu 14.10x32). I don't think it is the cause of my problem but I am just stating a fact.

Thank you

fcortes commented Oct 13, 2015

Instead of doing this
$ cat ~/.ssh/id_rsa.pub | ssh -p 22 username@123.123.123.123 'cat >> ~/.ssh/authorized_keys'
You can just run
$ ssh-copy-id "username@123.123.123.123 -p 22"

hi @LinKassem
i am also in the same issue as you have , did u manage to get your problem fixed ,
if yes please help me !

Maroo-b commented Nov 8, 2015

Hi @sudhirsb2003, if you get a blank page when you point to your server IP you should add a root path to your config/routes.rb file.

You need to download GPG signature before installing RVM:

gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

Is correct? listen '/tmp/unicorn.spui.sock', backlog: 64 .... Or is /tmp/unicorn.my_app.sock?

chai2 commented Feb 3, 2016

This is so awesome. thanks man..(beer)

Devise.secret_key was not set. Please add the following to your Devise initializer:

config.secret_key = '5437bfee6a5748d....asda'
i have problem, this error was i not set secret_key for devise, but i have config it on devise.rb, still have , please help me

alexonozor commented Oct 23, 2016 edited

After following your instructions I am getting "we are sorry something went wrong" I don't know what's wrong since I can see the server tail of debugging. Please come to my aid. Thanks in Advance.

nodox commented Feb 14, 2017

I'm getting the same error as @alexonozor
Any idea?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment