How to Deploy Ruby on Rails Apps on AWS EC2

Manish Yadav
9 min readSep 13, 2017

--

Amazon Elastic Compute Cloud (EC2) forms a central part of Amazon.com’s cloud-computing platform, Amazon Web Services (AWS), by allowing users to rent virtual computers on which to run their own computer applications.

Today I am going to tell you how to deploy rails web application on Amazon Ec2 instances.

FIRST THING is Create a AWS account , Link .

After creating account you’ll be getting screen like this , its aws console

So Lets begin deploying Rails app on Amazon Web Services

•First thing we need to do is to set up a instance in which our rails app is to be deployed. So just follow the steps :

•From the console Click on EC2 option which will take us to EC2 Dashboard where it will show the current status of the Amazon EC2 resources

Click on Launch Instance option below

Then we are headed to a page that will ask for the Amazon Machine Image which means that what base Operating System we want in our servers , so in this tutorial i am using ubuntu 16.04 . Different images have different configurations packages and libraries installed on it.

STEP 1 :Select the Ubuntu Server 16.04 LTS (HVM), SSD Volume Type

Amazon Machine Image

So the next step tells us the type of machine and the configurations that are required in the image like CPUs Memory etc ,

STEP 2:Click on Next:Configure Instance Details ,just let it remain as it is , if you want to know about the other configurations prices etc you can check this link.

STEP 3:Let it also as it is and click on Next:Add storage

Now in this step we can modify the storage space that we require by default its 8GB but we can modify it .AWS gives new users one year free trial for deployments , and storage upto 30GB in a image.So in the previous step we can increase it upto 30Gb and it will not cost us, 8Gb is also enough.

STEP 4 :Click on Next:Add Tags nothing to do here, ignore it

STEP 5:Click on Next:Configure Security Group

Now this part is important part

By default our machine is deployed on Amazon’s cloud somewhere and in order to gain access to it we need to open permissions on their machine through security group that will allow us on our host machine(my laptop) to gain access of that device ,

STEP 6:Then we should edit the rule for SSH(secure shell) that source option should be anywhere

and Custom TCP with post 80 and also source option should be anywhere

STEP 7 :Then the final step click on Review and launch .

It will ask for the key pair create a new key pair and it will automatically downloads. Add name for the key pair suppose “demo”

file downloaded will be like demo.pem

KEY PAIR is required to connect to the machine from our local computer in order to take access. It is private access key and we should not share this to anyone.

So when we go back to our console and open the open the Running instances we have the running instances.

Here we can see the public IPv4 public IP

CONNECTING THE MACHINE FROM TERMINAL

Open up terminal and go inside the Downloads directory where the Key pair is downloaded

MANISHs-MacBook-Air:Downloads manishyadav$ sudo chmod 400 demo.pem

To connect from terminal

MANISH-MacBook-Air:Downloads manishyadav$ ssh -i demo.pem ubuntu@IPv4 public IP

Now we are connected with our machine hosted , we need to add rails and other dependencies

FOLLOW the commands for installation

(Link followed for installation : Digital Ocean)

ubuntu@ip-172-31-17-122:sudo apt-get update

Install the rbenv and Ruby dependencies with apt-get:

$sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev

Now we are ready to install rbenv. The easiest way to do that is to run these commands, as the user that will be using Ruby:

(changed bash_profile to bashrc)

$git clone git://github.com/sstephenson/rbenv.git .rbenv$echo ‘export PATH=”$HOME/.rbenv/bin:$PATH”’ >> ~/.bashrc$echo ‘eval “$(rbenv init -)”’ >> ~/.bashrc$git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build$echo ‘export PATH=”$HOME/.rbenv/plugins/ruby-build/bin:$PATH”’ >> ~/.bashrc$source ~/.bashrc

Install Ruby

$rbenv install -v 2.2.3
$rbenv global 2.2.3

It is likely that you will not want Rubygems to generate local documentation for each gem that you install, as this process can be lengthy. To disable this, run this command:

$echo “gem: --no-document” > ~/.gemrc

Install Rails

$gem install rails
$rbenv rehash

Verify that Rails has been installed properly by printing its version, with this command:

$rails -v

Install Javascript Runtime

A few Rails features, such as the Asset Pipeline, depend on a Javascript runtime. We will install Node.js to provide this functionality.

Add the Node.js PPA to apt-get:

$sudo add-apt-repository ppa:chris-lea/node.js

Then update apt-get and install the Node.js package:

$sudo apt-get update
$sudo apt-get install nodejs

Congratulations! Ruby on Rails is now installed on your system.

FOR DB we are using POSTGRES

(Link followed for installation : Digital Ocean)

Postgres Installation

$sudo apt-get update
$sudo apt-get install postgresql postgresql-contrib

So mostly everything is setted up

Now clone the repository from github and CREATE & MIGRATE THE DATABASE( note that your REPO/config/database.yml should have production creadentials like database/username/password etc)

mine REPO/config/database.yml was like this

# SQLite version 3.x
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
#
default: &default
adapter: postgresql
pool: 5
timeout: 5000
encoding: unicode

development:
<<: *default
database: infox

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: infox

production:
<<: *default
host: localhost
database: infox17
username: infox17
password: infox17

So for database creation and migration we should have to create user we get error like this

PG::ConnectionBad
FATAL: role "Myname" does not exist

Creating user :Follow this

$sudo -i -u postgres
$psql
$create user infox17 with password 'infox17';
$create database alpha_database owner infox17;
$alter user infox17 superuser createrole createdb replication;
$\q
$exit

Now go inside the cloned REPO

$cd REPO
$sudo apt-get install libpq-dev
$bundle install
$RAILS_ENV=production bundle exec rake db:create
$rake db:migrate RAILS_ENV=production

We need to setup BASH PROFILE for our rails app to run

$cd
$vim .bash_profile

Add this line in the last of the bash_profile opened

->press i
than add this line in bottom
->export RAILS_ENV=”production”
->press esc
->press :wq
->press enter
-> type source .bash_profile

Than

$cd REPO
$ rake secret
$ {copy the secret generated}
$cd
$vim .bash_profile
->press i
than add this line in bottom
export SECRET_KEY_BASE="paste the previously copied secret"
->press esc
->press :wq
->press enter
-> type source .bash_profile
$

ADDING UNICORN AND NGINX APP SERVERS

Install Unicorn

(Link followed for installation : Digital Ocean)

An easy way to do this is to add it to your application’s Gemfile. Open the Gemfile in your favorite editor (make sure you are in your application's root directory):

$vi Gemfile

At the end of the file, add the Unicorn gem with this line:

gem 'unicorn'

Save and exit.

To install Unicorn, and any outstanding dependencies, run Bundler:

$bundle

Unicorn is now installed, but we need to configure it.

Configure Unicorn

Add this file in the config folder in rails app

Let’s add our Unicorn configuration to config/unicorn.rb. Open the file in a text editor:

$vi config/unicorn.rb

Copy and paste this configuration into the file:

# set path to application
app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"
working_directory app_dir
# Set unicorn options
worker_processes 2
preload_app true
timeout 30
# Set up socket location
listen "#{shared_dir}/sockets/unicorn.sock", :backlog => 64
# Logging
stderr_path "#{shared_dir}/log/unicorn.stderr.log"
stdout_path "#{shared_dir}/log/unicorn.stdout.log"
# Set master PID location
pid "#{shared_dir}/pids/unicorn.pid"

Save and exit. This configures Unicorn with the location of your application, and the location of its socket, logs, and PIDs. Feel free to modify the file, or add any other options that you require.

Now create the directories that were referred to in the configuration file:

$cd REPO
$mkdir -p shared/pids shared/sockets shared/log

Create Unicorn Init Script

Let’s create an init script so we can easily start and stop Unicorn, and ensure that it will start on boot.

Create a script and open it for editing with this command (replace the highlighted part with your application name, if you wish):

$sudo vi /etc/init.d/unicorn_REPO

Copy and paste the following code block into it, and be sure to substitute USER and APP_NAME(highlighted) with the appropriate values:

We have USER=ubuntu and APP_NAME=REPO

#!/bin/sh### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the unicorn app server
# Description: starts unicorn using start-stop-daemon
### END INIT INFO
set -eUSAGE="Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"# app settings
USER="ubuntu"
APP_NAME="REPO"
APP_ROOT="/home/$USER/$APP_NAME"
ENV="production"
# environment settings
PATH="/home/$USER/.rbenv/shims:/home/$USER/.rbenv/bin:$PATH"
CMD="cd $APP_ROOT && bundle exec unicorn -c config/unicorn.rb -E $ENV -D"
PID="$APP_ROOT/shared/pids/unicorn.pid"
OLD_PID="$PID.oldbin"
# make sure the app exists
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $OLD_PID && kill -$1 `cat $OLD_PID`
}
case $1 in
start)
sig 0 && echo >&2 "Already running" && exit 0
echo "Starting $APP_NAME"
su - $USER -c "$CMD"
;;
stop)
echo "Stopping $APP_NAME"
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
echo "Force stopping $APP_NAME"
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload|upgrade)
sig USR2 && echo "reloaded $APP_NAME" && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && exit 1
;;
*)
echo >&2 $USAGE
exit 1
;;
esac

Save and exit. This will allow you to use service unicorn_appname to start and stop your Unicorn and your Rails application.

Update the script’s permissions and enable Unicorn to start on boot:

$sudo chmod 755 /etc/init.d/unicorn_REPO
$sudo update-rc.d unicorn_REPO defaults

Let’s start it now:

$sudo service unicorn_REPO start

Now your Rails application’s production environment is running under Unicorn, and it’s listening on the shared/sockets/unicorn.sock socket. Before your application will be accessible to an outside user, you must set up the Nginx reverse proxy.

Install and Configure Nginx

Install Nginx using apt-get:

$sudo apt-get install nginx

Now open the default server block with a text editor:

$sudo vi /etc/nginx/sites-available/default

Replace the contents of the file with the following code block. Be sure to replace the the highlighted parts with the appropriate username and application name:

upstream app {
# Path to Unicorn SOCK file, as defined previously
server unix:/home/ubuntu/REPO/shared/sockets/unicorn.sock fail_timeout=0;
}
server {
listen 0.0.0.0;
server_name localhost;
root /home/ubuntu/REPO/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;
}

Save and exit. This configures Nginx as a reverse proxy, so HTTP requests get forwarded to the Unicorn application server via a Unix socket. Feel free to make any changes as you see fit.

Restart Nginx to put the changes into effect:

$sudo service nginx restart

NOW VISIT TO THAT IPv4 public IP and your rails app is LIVE.

Thanks for reading

Please feel free to ask for help below if required.

--

--