Skip to content

Instantly share code, notes, and snippets.

@qheuristics
Forked from JamesDullaghan/digitalocean.md
Last active August 29, 2015 14:12
Show Gist options
  • Select an option

  • Save qheuristics/e534c9b629c4f72e7d50 to your computer and use it in GitHub Desktop.

Select an option

Save qheuristics/e534c9b629c4f72e7d50 to your computer and use it in GitHub Desktop.

Revisions

  1. James Dullaghan revised this gist Jul 6, 2013. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions digitalocean.md
    Original file line number Diff line number Diff line change
    @@ -358,6 +358,14 @@ after deploy:cold
    sudo rm /etc/nginx/sites-enabled/default
    sudo service nginx restart
    sudo update-rc.d -f unicorn_projectname defaults

    Make changes and deploy

    # Make changes
    git add .
    git commit -m "Changes"
    git push origin master
    cap deploy

    Resources from Railscasts/digital ocean documentation.
    For use if puppet or chef is a little over your head.
  2. James Dullaghan created this gist Jul 6, 2013.
    366 changes: 366 additions & 0 deletions digitalocean.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,366 @@
    ### Deploy Rails app to digitalocean with nginx, unicorn, capistrano & postgres

    Create droplet of your liking (ubuntu 12.10 x32)

    ssh to root in terminal with your server ip

    ssh [email protected]

    Add ssh fingerprint and enter password provided in email

    Change password

    passwd

    Create new user

    adduser username

    Set new users privileges

    visudo

    Find user privileges section

    # User privilege specification
    root ALL=(ALL:ALL) ALL

    Add your new user privileges under root & cntrl+x then y to save

    username ALL=(ALL:ALL) ALL

    Configure SSH

    nano /etc/ssh/sshd_config

    Find and change port to one that isn't default(22 is default: choose between 1025
    ..65536)

    Port 22 # change this to whatever port you wish to use
    Protocol 2
    PermitRootLogin no

    Add to bottom of sshd_config file after changing port (cntrl+x then y to save)

    UseDNS no
    AllowUsers username

    Reload ssh

    reload ssh

    Don't close root! Open new shell and ssh to vps with new username(remember the port, or you're locked out!)

    ssh -p 1026 [email protected]

    Update packages on virtual server

    sudo apt-get update
    sudo apt-get install curl

    install latest stable version of rvm

    curl -L get.rvm.io | bash -s stable

    load rvm

    source ~/.rvm/scripts/rvm

    install rvm dependencies

    rvm requirements

    Install ruby 2.0.0

    rvm install 2.0.0

    Use 2.0.0 as rvm default

    rvm use 2.0.0 --default

    install latest version of rubygems if rvm install didn't

    rvm rubygems current

    install rails gem

    gem install rails --no-ri --no-rdoc

    Install postgres

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

    Create new postgres user

    sudo -u postgres psql
    create user username with password 'password';
    alter role username superuser createrole createdb replication;
    create database projectname_production owner username;

    Install git-core

    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
    cd /etc/nginx

    local unicorn setup

    Add unicorn to the gemfile
    create unicorn.rb & unicorn_init.sh file
    chmod +x config/unicorn_init.sh

    nginx.conf (change projectname and username to match your directory structure!)
    upstream unicorn {
    server unix:/tmp/unicorn.projectname.sock fail_timeout=0;
    }

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

    location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control 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;
    }

    config/unicorn.rb

    root = "/home/username/apps/projectname/current"
    working_directory root
    pid "#{root}/tmp/pids/unicorn.pid"
    stderr_path "#{root}/log/unicorn.log"
    stdout_path "#{root}/log/unicorn.log"

    listen "/tmp/unicorn.projectname.sock"
    worker_processes 2
    timeout 30

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

    config/unicorn_init.sh

    #!/bin/sh
    ### BEGIN INIT INFO
    # Provides: unicorn
    # Required-Start: $remote_fs $syslog
    # Required-Stop: $remote_fs $syslog
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: Manage unicorn server
    # Description: Start, stop, restart unicorn server for a specific application.
    ### END INIT INFO
    set -e

    # Feel free to change any of the following variables for your app:
    TIMEOUT=${TIMEOUT-60}
    APP_ROOT=/home/username/apps/projectname/current
    PID=$APP_ROOT/tmp/pids/unicorn.pid
    CMD="cd $APP_ROOT; bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb -E production"
    AS_USER=username
    set -u

    OLD_PIN="$PID.oldbin"

    sig () {
    test -s "$PID" && kill -$1 `cat $PID`
    }

    oldsig () {
    test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
    }

    run () {
    if [ "$(id -un)" = "$AS_USER" ]; then
    eval $1
    else
    su -c "$1" - $AS_USER
    fi
    }

    case "$1" in
    start)
    sig 0 && echo >&2 "Already running" && exit 0
    run "$CMD"
    ;;
    stop)
    sig QUIT && exit 0
    echo >&2 "Not running"
    ;;
    force-stop)
    sig TERM && exit 0
    echo >&2 "Not running"
    ;;
    restart|reload)
    sig HUP && echo reloaded OK && exit 0
    echo >&2 "Couldn't reload, starting '$CMD' instead"
    run "$CMD"
    ;;
    upgrade)
    if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
    then
    n=$TIMEOUT
    while test -s $OLD_PIN && test $n -ge 0
    do
    printf '.' && sleep 1 && n=$(( $n - 1 ))
    done
    echo

    if test $n -lt 0 && test -s $OLD_PIN
    then
    echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
    exit 1
    fi
    exit 0
    fi
    echo >&2 "Couldn't upgrade, starting '$CMD' instead"
    run "$CMD"
    ;;
    reopen-logs)
    sig USR1
    ;;
    *)
    echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
    exit 1
    ;;
    esac

    Add capistrano and rvm capistrano to gemfile

    gem 'capistrano'
    gem 'rvm-capistrano'

    Create capfile & config/deploy.rb files

    capify .

    deploy.rb

    require "bundler/capistrano"
    require "rvm/capistrano"

    server "123.123.123.123", :web, :app, :db, primary: true

    set :application, "projectname"
    set :user, "username"
    set :port, 22
    set :deploy_to, "/home/#{user}/apps/#{application}"
    set :deploy_via, :remote_cache
    set :use_sudo, false

    set :scm, "git"
    set :repository, "[email protected]:username/#{application}.git"
    set :branch, "master"


    default_run_options[:pty] = true
    ssh_options[:forward_agent] = true

    after "deploy", "deploy:cleanup" # keep only the last 5 releases

    namespace :deploy do
    %w[start stop restart].each do |command|
    desc "#{command} unicorn server"
    task command, roles: :app, except: {no_release: true} do
    run "/etc/init.d/unicorn_#{application} #{command}"
    end
    end

    task :setup_config, roles: :app do
    sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
    sudo "ln -nfs #{current_path}/config/unicorn_init.sh /etc/init.d/unicorn_#{application}"
    run "mkdir -p #{shared_path}/config"
    put File.read("config/database.example.yml"), "#{shared_path}/config/database.yml"
    puts "Now edit the config files in #{shared_path}."
    end
    after "deploy:setup", "deploy:setup_config"

    task :symlink_config, roles: :app do
    run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
    end
    after "deploy:finalize_update", "deploy:symlink_config"

    desc "Make sure local git is in sync with remote."
    task :check_revision, roles: :web do
    unless `git rev-parse HEAD` == `git rev-parse origin/master`
    puts "WARNING: HEAD is not the same as origin/master"
    puts "Run `git push` to sync changes."
    exit
    end
    end
    before "deploy", "deploy:check_revision"
    end

    Capfile

    load 'deploy'
    load 'deploy/assets'
    load 'config/deploy'

    Shake hands with github

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

    Add ssh key to digitalocean

    cat ~/.ssh/id_rsa.pub | ssh -p 22 [email protected] 'cat >> ~/.ssh/authorized_keys'

    Create repo and push to github

    # Add config/database.yml to .gitignore
    cp config/database.yml config/database.example.yml
    git init
    git add .
    git commit -m "Inital Commit"
    git remote add origin [email protected]:username/reponame
    git push origin master

    deployment

    cap deploy:setup
    # edit /home/username/apps/projectname/shared/config/database.yml on server
    cap deploy:cold

    after deploy:cold

    sudo rm /etc/nginx/sites-enabled/default
    sudo service nginx restart
    sudo update-rc.d -f unicorn_projectname defaults

    Resources from Railscasts/digital ocean documentation.
    For use if puppet or chef is a little over your head.
    I know you can spawn up a rails app using nginx and unicorn with mysql, but you don't learn much that way!

    Hopefully I didn't miss any steps, although I'm sure I did. Please leave comments if you run into troubles.