Skip to content

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@

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@

Install Curl

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

Install RVM

$ curl -L | 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;
  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/"

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',

  defined?(ActiveRecord::Base) and

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

  defined?(ActiveRecord::Base) and

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

Add Capistrano

$ vim Gemfile

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

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, ''

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'

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/ | ssh -p 22 username@ 'cat >> ~/.ssh/authorized_keys'

Say Hi to Github

# follow the steps in this guide if receive permission denied(public key)
$ ssh    

Check Deployment (Commit and Push)

$ cap production deploy:check


$ cap production deploy

Thanks to James Dullaghan for his help.


This comment has been minimized.

Copy link

LinKassem commented Apr 20, 2015

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


This comment has been minimized.

Copy link

fcortes commented Oct 13, 2015

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


This comment has been minimized.

Copy link

sudhirsb2003 commented Nov 3, 2015

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 !


This comment has been minimized.

Copy link

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.


This comment has been minimized.

Copy link

sergiogomez commented Dec 29, 2015

You need to download GPG signature before installing RVM:

gpg --keyserver hkp:// --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3


This comment has been minimized.

Copy link

BrunoQuaresma commented Jan 13, 2016

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


This comment has been minimized.

Copy link

chai2 commented Feb 3, 2016

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


This comment has been minimized.

Copy link

thongdinh commented Mar 16, 2016

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

config.secret_key = ''
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


This comment has been minimized.

Copy link

alexonozor commented Oct 23, 2016

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.


This comment has been minimized.

Copy link

nodox commented Feb 14, 2017

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


This comment has been minimized.

Copy link

paudelprerana commented Jun 12, 2017

hello @ChuckJHardy, what configs do I have to specify, in case I have to restart two unicorn workers with different ports and restart a resque server?


This comment has been minimized.

Copy link

jlgasparrini commented Jul 12, 2017

Hi everybody! Is it necessary the file in /etc/default/unicorn?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.