Skip to content

Instantly share code, notes, and snippets.

@konung
Forked from deHelden/"torn" 1 Setup vps.md
Created February 5, 2023 21:38
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 konung/c4217477d40635547b74dfdbc64ef1e5 to your computer and use it in GitHub Desktop.
Save konung/c4217477d40635547b74dfdbc64ef1e5 to your computer and use it in GitHub Desktop.
Deploy Rails 6.0.0 to VPS(DigitalOcean Ubuntu 19). Nginx, Puma, Capistrano3, PostgreSQL, Rbenv.

SETUP VPS

based on DigitalOcean guide

Create local project

local$ rails new appname -T -d postgresql
local$ rails g scaffold Story title:string body:text
local$ rails db:migrate

Go to Step 1.1 "Create deploy user" (remote root$)


Go to Step 1.2 "Setup rbenv ruby rails nginx postgresql" (remote deploy$)


Setup ssh for GitHub

deploy$ ssh-keygen -t rsa # Add the newly created public key (~/.ssh/id_rsa.pub) to your repository’s deployment keys

Go to step 2 "Setup local Capistrano"


Go to step 3 "Setup local Capfile"


Go to step 4 "Setup local deploy.rb file"


Go to step 5 "Setup local nginx.conf file"


DEPLOYING RAILS APP

local$ git add -A
local$ git commit -m "Set up Puma, Nginx & Capistrano"
local$ git push origin master

sharing creds based on Medium column

Copy config/master.key from local filesystem to the production server under appname/shared/config/master.key

local$ cap production deploy:initial

Reboot Nginx

deploy$ sudo rm /etc/nginx/sites-enabled/default
deploy$ sudo ln -nfs "/home/deploy/apps/appname/current/config/nginx.conf" "/etc/nginx/sites-enabled/appname"
deploy$ sudo service nginx restart
root# apt update && apt upgrade

root# adduser deploy
root# gpasswd -a deploy sudo

# optional
root# vim /etc/ssh/sshd_config
# CHANGE `PermitRootLogin no` 
root# service ssh restart

root# exit
deploy$ sudo apt -y install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev libffi-dev

## For rails 6 also should be installed node.js & yarn
## God forbid you should do it with nvm. RIP this way

deploy$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
deploy$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
deploy$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc &&  source ~/.bashrc 
deploy$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
deploy$ rbenv install 2.6.3 && rbenv global 2.6.3
deploy$ echo "gem: --no-document" > ~/.gemrc
deploy$ gem install bundler
deploy$ gem install rails -v 6.0.0 --no-document

deploy$ sudo apt install curl git-core nginx -y

deploy$ sudo apt -y install postgresql postgresql-contrib libpq-dev
deploy$ sudo pg_createcluster 11 main --start
deploy$ sudo -u postgres createuser deploy -s
deploy$ sudo -u postgres psql
postgres=# \password deploy
postgres=# create database appname;
postgres=# \q
ADD_TO_Gemfile:
group :development do
gem 'capistrano', require: false
gem 'capistrano-rbenv', require: false
gem 'capistrano-rails', require: false
gem 'capistrano-bundler', require: false
gem 'capistrano3-puma', require: false
end
RUN:
cap install
# Load DSL and set up stages
require "capistrano/setup"
# Include default deployment tasks
require "capistrano/deploy"
require "capistrano/rbenv"
require "capistrano/bundler"
require "capistrano/rails"
require "capistrano/puma"
install_plugin Capistrano::Puma
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
# Change these
server 'your_server_ip', port: your_port_num, roles: [:web, :app, :db], primary: true # port_num is optional can be removed
set :repo_url, 'git@example.com:username/appname.git'
set :application, 'appname'
set :user, 'deploy'
set :puma_threads, [4, 16]
set :puma_workers, 0
# Don't change these unless you know what you're doing
set :pty, true
set :use_sudo, false
set :stage, :production
set :deploy_via, :remote_cache
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :ssh_options, { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true # Change to false when not using ActiveRecord
## Defaults:
# set :scm, :git
# set :branch, :master
# set :format, :pretty
# set :log_level, :debug
# set :keep_releases, 5
## Linked Files & Directories (Default None):
# set :linked_files, %w{config/database.yml}
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
set :linked_files, %w{config/master.key}
namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) 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
end
desc 'Initial Deploy'
task :initial do
on roles(:app) do
before 'deploy:restart', 'puma:start'
invoke 'deploy'
end
end
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
invoke 'puma:restart'
end
end
before :starting, :check_revision
after :finishing, :compile_assets
after :finishing, :cleanup
after :finishing, :restart
end
# ps aux | grep puma # Get puma pid
# kill -s SIGUSR2 pid # Restart puma
# kill -s SIGTERM pid # Stop puma

Create config/nginx.conf in your Rails project directory add the following to it (again, replacing with your parameters):


upstream puma {
  server unix:///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
}

server {
  listen 80 default_server deferred;
  # server_name example.com;

  root /home/deploy/apps/appname/current/public;
  access_log /home/deploy/apps/appname/current/log/nginx.access.log;
  error_log /home/deploy/apps/appname/current/log/nginx.error.log info;

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

  try_files $uri/index.html $uri @puma;
  location @puma {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://puma;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 10M;
  keepalive_timeout 10;
}
Capistrano::Rails::Db
cap production deploy:db:abort_if_pending_migrations # Run rake db:abort_if_pending_migrations
cap production deploy:db:create # Run rake db:create
cap production deploy:db:drop # Run rake db:drop
cap production deploy:db:migrate # Run rake db:migrate Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
cap production deploy:db:migrate:down # Run rake db:migrate:down Run the "down" for a given migration VERSION
cap production deploy:db:migrate:redo # Run rake db:migrate:redo Rollback the database one migration and re migrate up (options: STEP=x, VERSION=x)
cap production deploy:db:migrate:reset # Run rake db:migrate:reset Reset your database using your migrations
cap production deploy:db:migrate:status # Run rake db:migrate:status Display status of migrations
cap production deploy:db:migrate:up # Run rake db:migrate:up Run the "up" for a given migration VERSION
cap production deploy:db:reset # Run rake db:reset Drop and recreate the database from db/schema.rb and load the seeds
cap production deploy:db:rollback # Run rake db:rollback Roll the schema back to the previous version (specify steps w/ STEP=n)
cap production deploy:db:seed # Run rake db:seed Load the seed data from db/seed.rb
cap production deploy:db:setup # Run rake db:setup Create the database, load the schema, and initialize with the seed data
cap production deploy:db:version # Run rake db:version Retrieve the current schema version number
Capistrano::Nginx
nginx:setup # creates /etc/nginx/sites-available/APPLICATION.conf and links it to /etc/nginx/sites-enabled/APPLICATION.conf
nginx:stop # invokes service nginx stop on server
nginx:start # invokes service nginx start on server
nginx:restart # invokes service nginx restart on server
nginx:reload # invokes service nginx reload on server
nginx:force-reload # invokes service nginx force-reload on server
nginx:enable_site # creates symlink in sites-enabled directory
nginx:disable_site # removes symlink from sites-enabled directory
Capistrano::Rails::Console
cap production rails:console # This will add a task rails:console
cap production rails:console sandbox=1 # You can also start a sandbox session
For more commands run:
cap -T
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment