Deploy your Rails app using EC2,Capistrano,Puma and NGINX

vedhagnanam
4 min readMar 5, 2020

Step 1: Create a new EC2 Instance

Log into the AWS console. Select EC2 and then Launch Instance:

Choose the type of Operating System for our virtual machine and select the type of Memory and CPU usage we want on our virtual machine

Allow HTTP requests by editing the security group of the instance

step 2: Add SSH

head over to your terminal and execute the command below to generate a new ssh key at ~/.ssh/id_rsa.pub

ssh-keygen -t rsacat ~/.ssh/id_rsa.pub

now connect to your instance by clicking the connect option in the aws console and following the instructions

now in the server edit the file authorized keys

sudo nano ~/.ssh/authorized_keys

and paste your ssh key. Now you can login to your instance by typing

ssh username@ip_address

Step 3: Install rvm

install rvm(Ruby Version Manager) using these commands

sudo apt-add-repository -y ppa:rael-gc/rvm
sudo apt-get update
sudo apt-get install rvm

after installing rvm you can install your required ruby version using

rvm install ruby

and install bundler using

gem install bundler

Step 4: Install and configure NGINX

Install nginx in the server using the following commands

apt-get update
apt-get install nginx

this will install nginx,start the server by executing the command

sudo service nginx start

now create a new file at nginx sites-available directory by using

sudo nano /etc/nginx/sites-available/app_name

add the following content and save the file

upstream puma {
server unix:///var/www/app_name/shared/tmp/sockets/app_name-puma.sock;
}

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

root var/www/app_name/current/public;
access_log var/www/app_name/current/log/nginx.access.log;
error_log var/www/app_name/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;
}

now remove the default page using the command

sudo rm /etc/nginx/sites-enabled/default

create a softlink of your config in sites-enabled

sudo ln -s /etc/nginx/sites-available/app_name /etc/nginx/sites-enabled/

Step 5: Add Capistrano to your project

open the Gemfile of your project and add

group :development do
gem ‘capistrano’, ‘~> 3.7’
gem ‘capistrano-rails’, ‘~> 1.2’
gem ‘capistrano-yarn’
gem ‘capistrano3-puma’
end

after adding the gems run this command

bundle installcap install 

this command will generate capfile.rb, deploy.rb and enviroinments for deployment

replace the contents of capfile.rb with


require “capistrano/setup”
require “capistrano/deploy”
require “capistrano/rails”
require “capistrano/puma”
install_plugin Capistrano::Puma
require “capistrano/yarn”
require “capistrano/bundler”
require “capistrano/scm/git”
install_plugin Capistrano::SCM::Git
install_plugin Capistrano::Puma::Nginx

Dir.glob(“lib/capistrano/tasks/*.rake”).each { |r| import r }

and deploy.rb with

set :application, “your_app_name”
set :repo_url, “repo_url”
# restart app by running: touch tmp/restart.txt
# at server machine
set :passenger_restart_with_touch, true
set :rails_env, :development
set :puma_threads, [4, 16]
# 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 :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 :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, false

set :deploy_to, “/var/www/app_name”
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

edit config/deploy/production.rb and replace it with

set :stage, :production
set :rails_env, :production
set :branch, “master”
server “your_ip_address”, user: “your_username”, roles: %w{web app db}

configure puma server by running the following command in the terminal

cap production puma:config

and to deploy run

cap production deploy

Congrats! If you enjoy the post please share. Thanks for reading

--

--