Skip to content

Instantly share code, notes, and snippets.

@sudhirsb2003
Last active August 9, 2019 05:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sudhirsb2003/f578e72f91a7bf60ad33fc561eaf74f4 to your computer and use it in GitHub Desktop.
Save sudhirsb2003/f578e72f91a7bf60ad33fc561eaf74f4 to your computer and use it in GitHub Desktop.
Ubuntu 14.04 x64 + Rails 4 + Nginx + Unicorn + PostgreSQL + Capistrano 3 Setup Instructions
### Ubuntu 14.04 x64 + Rails 4 + Nginx + Unicorn + PostgreSQL + Capistrano 3
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
Create Unicorn Init Script
Let's create an init script so we can easily start and stop Unicorn, and ensure that it will start on boot.
Create a script and open it for editing with this command (replace the unicorn_app part with your application name, if you wish):
sudo vi /etc/init.d/unicorn_appname
Copy and paste the following code block into it, and be sure to substitute USER and APP_NAME with the appropriate values
#!/bin/sh
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the unicorn app server
# Description: starts unicorn using start-stop-daemon
### END INIT INFO
set -e
USAGE="Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
# app settings
USER="deploy"
APP_NAME="appname"
APP_ROOT="/home/$USER/$APP_NAME"
ENV="production"
# environment settings
PATH="/home/$USER/.rbenv/shims:/home/$USER/.rbenv/bin:$PATH"
CMD="cd $APP_ROOT && bundle exec unicorn -c config/unicorn.rb -E $ENV -D"
PID="$APP_ROOT/shared/pids/unicorn.pid"
OLD_PID="$PID.oldbin"
# make sure the app exists
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $OLD_PID && kill -$1 `cat $OLD_PID`
}
case $1 in
start)
sig 0 && echo >&2 "Already running" && exit 0
echo "Starting $APP_NAME"
su - $USER -c "$CMD"
;;
stop)
echo "Stopping $APP_NAME"
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
echo "Force stopping $APP_NAME"
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload|upgrade)
sig USR2 && echo "reloaded $APP_NAME" && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && exit 1
;;
*)
echo >&2 $USAGE
exit 1
;;
esac
Save and exit. This will allow you to use service unicorn_appname to start and stop your Unicorn and your Rails application.
Update the script's permissions and enable Unicorn to start on boot:
sudo chmod 755 /etc/init.d/unicorn_appname
sudo update-rc.d unicorn_appname defaults
Let's start it now:
sudo service unicorn_appname start
Now your Rails application's production environment is running under Unicorn, and it's listening on the shared/sockets/unicorn.sock socket.
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](https://gist.github.com/JamesDullaghan/5941259) for his help.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment