How to deploy your rails app to Amazon EC2 using Capistrano, nginx and puma.
step 1 — create a simple rails application
step 2 — push that app on github.
step 3 — create your Amazon EC2 Instance.
Go to Amazon AWS Console
https://console.aws.amazon.com/
Sign in, or sign up.
Once you’re logged in and have an account ready to go, click Services.
In the dropdown menu, select EC2 under the Compute menu.
On this new page, click Launch Instance.
Choose the Ubuntu Server 18.04 LTS (HVM), SSD Volume Type.
Click the Select button.
Since this is a starter project, I’m going to choose the t2.micro instance, eligible for the free tier.
Click Next: Configure Instance Details — nothing to change here, unless you want to.
Click Next: Add Storage — I’m going to keep the defaults here, as well, since this is really just a proof of concept kind of thing.
Click Next: Add Tags — again, nothing to go here.
Click Next: Configure Security Group
- Select the Create a new security group radio button
- There’s already an SSH open on port 22 to 0.0.0.0/0
- Next, add a new rule. Here’s what I created:
Security rule settings:
- Type:
Custom TCP
- Protocol:
TCP
- Port Range:
80
- Source:
Custom: 0.0.0.0/0
Keeping port 80 open to the world is desired behaviour — you want anyone to be able to access your site once it’s live.
Click Review and Launch
Confirm everything looks the way you want, and finally click Launch.
Amazon will ask you to select an existing key pair or create a new key pair. I’m assuming you either haven’t done this before (and therefore have no key pair), or, like me, are trying to set up a fully sandboxed Rails App. So let’s select Create a new key pair.
and name key-value pair.
click download key-value pair. save the file. and click launch the instance.
step 4 — now find the downloaded key-value pair and navigate to that folder.
i have put that key in server-keys folder so
Then you’ll want to connect to your instance using its Public DNS.
The command looks like ssh -i "filterrific-key-pair.pem" ubuntu@some-dns.computer.amazon.aws
.
If you need a more specific command for your keypair name and DNS address, click the Connect button in the Amazon Resource Groups panel.
after that command you will be in a shell prompt which looks like:-
step 5 — set up Capistrano in your rails project:-
gem ‘capistrano’
gem ‘capistrano-rails’
gem ‘capistrano-bundler’
gem ‘capistrano-rbenv’
gem ‘capistrano3-puma’
and then do bundle install.
If everything worked, go ahead and commit this change.
Now generate the Capistrano config files by running-
cap install STAGES=production
This creates three files: Capfile
, config/deploy.rb
and config/deploy/production.rb
.
and in Capfile uncomment the following lines:-
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
require "capistrano/rbenv"
require 'capistrano/puma'
install_plugin Capistrano::Puma //you have to add this
now setup deploy.rb file to look like this:-
# config valid for current version and patch releases of Capistranolock "~> 3.16.0"set :application, "demo_app"set :repo_url, 'https://github.com/shreya-bacancy/demo_app.git'set :deploy_to, '/home/ubuntu/demo_app'set :use_sudo, trueset :branch, 'master'set :linked_files, %w{config/master.key config/database.yml}set :rails_env, 'production'set :keep_releases, 2set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :linked_files, %w{config/database.yml config/master.key}# Default branch is :master# ask :branch, `git rev-parse --abbrev-ref HEAD`.chompset :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.access.log"set :puma_error_log, "#{release_path}/log/puma.error.log"set :ssh_options, { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }set :puma_preload_app, trueset :puma_worker_timeout, nilset :puma_init_active_record, true # Change to false when not using ActiveRecordnamespace :puma dodesc 'Create Directories for Puma Pids and Socket'task :make_dirs doon roles(:app) doexecute "mkdir #{shared_path}/tmp/sockets -p"execute "mkdir #{shared_path}/tmp/pids -p"endendbefore :start, :make_dirsend
now we will configure production.rb
server '65.2.73.207', user: 'ubuntu', roles: %w{web app db}
set :ssh_options, {
forward_agent: true,
auth_methods: %w[publickey],
keys: %w[/home/shreya/server-keys/filterrific-key-pair.pem]
}
step 6 — prepare server to run Capistrano tasks-
firstly run your server:-
shreya@shreya-Vostro-3500:~ $ ssh -i ~/server-keys/filterrific-key-pair.pem ubuntu@ec2-65-2-73-207.ap-south-1.compute.amazonaws.com
Create the directory that the app will live in: (make sure that you are in server console)
ubuntu@ip-172-31-4-157:~$ sudo mkdir -p /var/www
By default, the ubuntu user doesn’t have access to this directory, so change the ownership:
ubuntu@ip-172-31-4-157:~$ sudo chown ubuntu /var/www
update all existing pacakge :-
ubuntu@ip-172-31-4-157:~$ sudo apt-get update && sudo apt-get -y upgrade
Then install all the dependencies required to install Ruby:
ubuntu@ip-172-31-4-157:~$ sudo apt install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm5 libgdbm-dev libsqlite3-dev
now install rbenv. Clone the rbenv repo:
ubuntu@ip-172-31-4-157:~$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
then, add ~/.rbenv/bin to your $PATH so you can use its CLI.
ubuntu@ip-172-31-4-157:~$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
Add this command to your bash profile so you can load rbenv automatically.
# ~
ubuntu@ip-172-31-4-157:~$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
Restart bash to get those changes to apply.
# ~
ubuntu@ip-172-31-4-157:~$ source ~/.bashrc
Then we'll install the ruby-build plugin to add rbenv install
which simplifies the install process for new Ruby versions (which we will surely need for Rails 6)
# ~
ubuntu@ip-172-31-4-157:~$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
Now you'll be able to see all the available ruby versions with this command:
# ~
ubuntu@ip-172-31-4-157:~$ rbenv install -l
For Rails 6, we need Ruby 2.5.0 or newer. At the time of writing, Rails 6 sets it at 2.5.1
# ~
ubuntu@ip-172-31-4-157:~$ rbenv install 2.5.1
The installation may take some time. This is a good spot to make some coffee.
Up next, set your global default ruby version using
# ~
ubuntu@ip-172-31-4-157:~$ rbenv global 2.5.1
You can check with
# ~
ubuntu@ip-172-31-4-157:~$ ruby -v
Now we need to configure our ability to work with gems. First, let's turn off local documentation generation by adding a setting to our ~/.gemrc
file
# ~
ubuntu@ip-172-31-4-157:~$ echo "gem: --no-document" > ~/.gemrc
With our gem process configured, let's install bundler. This step gave me issues before, and I realized I installed the latest bundler, but Rails 6 generated using 1.17.1. Make sure to specify your version - the version you download on the server should match what's written in your Gemfile.
# ~
ubuntu@ip-172-31-4-157:~$ gem install bundler -v 1.17.1
Now update all pacakage and install NodeJs pacakage
ubuntu@ip-172-31-4-157:~$ sudo apt-get install nodejs
now install npm
ubuntu@ip-172-31-4-157:~$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
ubuntu@ip-172-31-4-157:~ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
ubuntu@ip-172-31-4-157:~$ sudo apt-get update
ubuntu@ip-172-31-4-157:~$ sudo apt-get install yarn
step 7–: Set up your EC2 server with your git credentials
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
it will prompt for a filename where you store your key, press enter to save it in default location.
also it will ask for passphrase but it is optional.
now go to ~/.ssh folder and run nano id_rsa.pub
Copy the content of above pub file, go to GitHub, click on Settings, then click SSH and GPG keys. Click New SSH key or Add SSH Key.
step 8 — Setup Nginx
now we install nginx on the server
ubuntu@ip-172-31-4-157:~$ sudo apt-get install nginx
Next, let’s configure the default server block:
# ~
ubuntu@ip-172-31-4-157:~$ sudo nano /etc/nginx/sites-available/default
And restart Nginx server -
ubuntu@ip-172-31-4-157:~$ sudo service nginx restart
Add the following in your file:-
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/home/ubuntu/demo_app/shared/tmp/sockets/demo_app-puma.sock;
}
server {listen 80;# If you're planning on using SSL (which you should), you can also go ahead and fill out the following server_name variable:
server_name localhost;# Don't forget to update these, too
root /home/ubuntu/demo_app/public;try_files $uri/index.html $uri @app;location @app {
proxy_pass http://app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
now save and exit.
step 9 — Commit your local changes to git and deploy to server
shreya@shreya-Vostro-3500:~/ROR/demo_app (master)$ git add .
shreya@shreya-Vostro-3500:~/ROR/demo_app (master)$ git commit -m "update with capistrano configuration"
shreya@shreya-Vostro-3500:~/ROR/demo_app (master)$ git push
shreya@shreya-Vostro-3500:~/ROR/demo_app (master)$ cap production deploy
step 10 — Go to browser and type your server public IP Address.
if everything works well!! then you see your rails app!!