Skip to content

Instantly share code, notes, and snippets.

@abratashov
Forked from ChuckJHardy/digital_ocean_setup.md
Last active June 8, 2020 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abratashov/6434b983507bdf127b21635c209cf8a5 to your computer and use it in GitHub Desktop.
Save abratashov/6434b983507bdf127b21635c209cf8a5 to your computer and use it in GitHub Desktop.
VPS Ubuntu 14.04(update to 16.04) x64 + Rails 4 + Nginx + Unicorn + MySQL + PostgreSQL + Capistrano 3 Setup Instructions

VPS Ubuntu 14.04(update to 16.04) x64 + Rails 4 + Nginx + Unicorn + MySQL + PostgreSQL + Capistrano 3

SSH into Root

local$ ssh root@123.123.123.123
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade
$ sudo apt-get install update-manager-core
$ sudo do-release-upgrade

Change Root Password

$ sudo passwd

Add Deploy User

$ sudo adduser deployer

Update Sudo Privileges (don't forget remove it after installing all you need)

$ sudo visudo
deployer ALL=(ALL:ALL) ALL

Configure SSH

$ sudo nano /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

Login with Deploy User

local$ ssh deployer@123.123.123.123

Add SSH Key to DigitalOcean

$ mkdir ~/.ssh
$ touch ~/.ssh/authorized_keys
local$ 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   

Install Curl

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

Step 02 - Install RVM

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

Install Bundler

$ gem install bundler

Step 03 - Install MySQL

$ sudo apt-get install mysql-server libmysql-ruby libmysqlclient-dev
$ gem install mysql2


# If you need import your DB:
# copy db file from your machine
$ scp ~/Path/database-name.sql deployer@123.123.123.123:/home/deployer/dest-folder
$ scp -r ~/Path/source-folder deployer@123.123.123.123:/home/deployer/dest-folder

# and import it into db (on server)
$ mysql
CREATE DATABASE database_name;
$ mysql -u username -p database_name < /home/deployer/dest-folder/database_name.sql

Step 04 - Install PostgreSQL

$ sudo apt-get install postgresql postgresql-server-dev-9.5
$ 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;

Step 05 - Install GIT

$ sudo apt-get install git-core

Step 06 - Install Sendmail

$ sudo nano /etc/hosts
127.0.0.1 localhost localhost.localdomain yourhostnamehere

$ sudo nano /etc/hostname
localhost
123.123.123.123

$ /etc/init.d/networking stop
$ /etc/init.d/networking start

$ sudo apt-get install sendmail
$ sudo sendmailconfig
$ echo "Subject: test" | sendmail yourname@gmail.com

Step 07 - Setup Nginx

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

upstream YOURAPP{
  server 127.0.0.1:4000 fail_timeout=0;
}

server {
  listen 80 default deferred;
  #server_name           YOURAPP.org.ua;
  root                  /var/www/current/public;
  #root                  /home/deployer/apps/YOURAPP/current/public

  location / {
    proxy_pass  http://YOURAPP;
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

    client_max_body_size       100m;
    client_body_buffer_size    128k;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
  }

  location ~ ^/(assets)/  {
    root /home/deployer/apps/YOURAPP/current/public;
    gzip_static on; # to serve pre-gzipped version
    expires max;
    add_header  Cache-Control public;
  }
}

$ sudo service nginx restart

Step 08 - Add Puma

$ nano Gemfile

gem 'puma'    

Step 09 - Add Capistrano

$ nano Gemfile

group :development do
  gem 'capistrano'#, '~> 3.6'
  gem 'capistrano-rails'#, '~> 1.2'
  gem 'capistrano-rvm'
  gem 'capistrano3-puma',   require: false
  gem 'steps', git: 'git@github.com:roman-franko/gem-steps.git'
end

Install Capistrano

$ bundle exec cap install

Update Capistrano Capfile

$ nano Capfile

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rvm'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/puma'
require 'capistrano/scm/git'
require 'whenever/capistrano'
# require 'capistrano/rails/db'
install_plugin Capistrano::SCM::Git

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

Update Capistrano Deploy Config

$ vim config/deploy.rb

# lock '3.4.0'

set :application,       "YOURAPP"

# set :scm,               :git
set :repo_url,          'git@bitbucket.org:REPO/YOURAPP.git'
set :branch,            ENV['BRANCH'] ? ENV['BRANCH'] : "master"
# ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call

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

set :linked_files,      %w{ config/database.yml
                            config/secrets.yml
                            config/mailer.yml }

set :linked_dirs,       %w{ bin
                            db/sphinx/demo/extracted_page_core
                            log
                            public/system
                            public/uploads
                            public/assets
                            tmp/pids
                            tmp/cache
                            tmp/sockets
                            tmp/binlog/demo
                            vendor/bundle }

set :assets_roles, [:web, :app]

set :rails_env,         "#{fetch(:stage)}"

set :bundle_binstubs, -> { shared_path.join('bin') }

set :puma_worker_timeout, nil
set :puma_init_active_record, true
set :puma_preload_app, true

# set :format,            ENV['DEBUG'] ? :pretty : :black_hole
set :log_level,         ENV['DEBUG'] ? :debug : :warn

Update Demo Deploy Config

$ nano config/deploy/demo.rb

set :user, 'deployer'

set :stage,       :demo
set :branch,      ENV['BRANCH'] || "master"
set :deploy_to,   "/home/#{fetch(:user)}/apps/#{fetch(:application)}"

server "123.123.123.123", user: "deployer", roles: %w{app db resque_worker}

# set :workers, { email: 1, carrierwave: 1 }

set :puma_bind, 'tcp://0.0.0.0:4000'
set :puma_threads, [1, 32]
set :puma_workers, 2

namespace :deploy do
  desc "Start application"
  task :start do
    # invoke 'resque:start'
  end

  desc "Stop application"
  task :stop do
    # invoke 'resque:stop'
  end

 desc "Restart application"
  task :restart do
    # invoke 'resque:restart'
  end

  after :publishing, :restart
  # after 'deploy:updated', 'deploy:db:migrate'

  after :finishing, 'deploy:cleanup'
end     

Check Deployment (Commit and Push)

$ cap demo deploy:check

Step 10 - Deploy

$ cap demo deploy

$ cap demo puma:start
$ cap demo puma:restart
$ cap demo puma:stop

Step 11 - Extra settings: Basic Firewal, Timezones, Swap File

  1. Close all you need portswith ufw
  2. Check ports with: nmap / zenmap netstat -tuna
  3. If need protection from DDos install 'fail2ban'

Step 12 - Remove Sudo Privileges

$ visudo
#deployer ALL=(ALL:ALL) ALL

Step 13 - Add helpful tools

  1. slap - text editor (like Sublime, for terminal)

Thanks to JHardy for his help.

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