Skip to content

Instantly share code, notes, and snippets.

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 alexandrule/67ad1e5fc740130c99a7339dc5d34988 to your computer and use it in GitHub Desktop.
Save alexandrule/67ad1e5fc740130c99a7339dc5d34988 to your computer and use it in GitHub Desktop.
Complete guide for deploying rails application to aws ec2 instance, using capistrano as deploying tool with nginx & puma server

Deploy Rails Application to AWS EC2

Creating AWS EC2 Instance

- login to 'AWS Management Console' (https://aws.amazon.com/console/)
- from 'Services'(in navbar) choose 'EC2'
- from 'Create Instance' section, click on 'Launch Instance'
- then select 'AMI' (Amazon Machine Image), we will be using 'Ubuntu Server 16.04 LTS (HVM)' as example
- select 'Instance Type' as per your requirement
- then click 'Next:Configure Instance Details' to continue
  change 'Configure Instance Details' or used as default settings
- click 'Next: Add Storage'
  adjust size as per your need (default is 8GB)
- click 'Next: Tag Instance'
  create tag if you need any tagging for your instance
- click 'Next: Configure Security Group'
  click 'Add Rule' to add new rule(for port, ip address etc.)
  default you can set it to -
  SSH      TCP     22     Anywhere     0.0.0.0/0
  HTTP     TCP     80     Anywhere     0.0.0.0/0 
- then click 'Review and Launch'
  check all your setting, then click 'Launch'
- select existing or create new keypair to connect to your instance
  click 'Launch Instance', this will generate the key (in case of new keypair) & launches your instance
  find 'Public IP' from 'Description'

Setup Elastic IP

- you can generate an Elastic IP from 'Network & Security' tab
- click 'Allocate new address'
- then click 'Allocate', this will generate an Elastic IP
- click 'Close', this will redirect you to Elastic IP Dashboard
- select you Elastic IP & on right click select 'Associate address'
- choose you instance (whom you want to associate) & click 'Associate'
  this will replace your Public IP with Elastic IP (& now this IP is used)

Setup the server to connect

#login to your server from terminal using pem file (generated private key)
- ssh -i "<Path of your pem file>" ubuntu@<Public IP Address>
- sudo apt-get update && sudo apt-get -y upgrade #to update existing packages
- sudo adduser deploy #create 'deploy' user for deploying the application to server
- sudo adduser deploy sudo #provide sudo privilege

Generating ssh-key

- su - deploy
- ssh-keygen #do not set a passphrase for the key
- cat .ssh/id_rsa.pub
- copy the ssh-key & set it as your deploy key on your repository(project on bitbucket or github)
- copy your system public ssh-key & paste it into the following file on your instance as deploy user
  nano .ssh/authorized_keys #save & exit

Installing GIT

- sudo apt-get install git

Installing Nginx

- sudo apt-get install nginx
- sudo nano /etc/nginx/sites-available/default #to configure default site
#add this content to file
upstream app {
  # Path to Puma SOCK file, as defined previously
  server unix:/home/deploy/<application name>/shared/tmp/sockets/puma.sock fail_timeout=0;
}

server {
  listen 80;
  server_name localhost;

  root /home/deploy/<application name>/current/public;

  try_files $uri/index.html $uri @app;

  location / {
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Connection '';
    proxy_pass http://app;
  }

  location ~ ^/(assets|fonts|system)/|favicon.ico|robots.txt {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

Installing ruby

- su - deploy
- sudo apt-get install libgdbm-dev libncurses5-dev automake libtool bison libffi-dev
- gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
- curl -sSL https://get.rvm.io | bash -s stable
- source ~/.rvm/scripts/rvm
- rvm install 2.5.1
- rvm use 2.5.1 --default
- ruby -v
- gem install bundler #install bundler

Installing NodeJs

- curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
- sudo apt-get install -y nodejs

Installing MySQL or PostgreSQL

# install mysql
- sudo apt-get install mysql-server mysql-client libmysqlclient-dev

# setup postgresql
- sudo sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
- wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
- sudo apt-get update
- sudo apt-get install postgresql-common
- sudo apt-get install postgresql-9.5 libpq-dev
# create postgresql user
- sudo -u postgres createuser foo -s
# set password
- sudo -u postgres psql
  postgres=# \password chris

Create files required by capistrano

- mkdir <application name>
- mkdir -p <application name>/shared/config
- nano <application name>/shared/config/database.yml

#for rails 5.2 'master.key' file is used for secret key
- nano <application name>/shared/config/master.key
- add key from master.key of your application to this file
  eg: da54dd7f691dd9d8707c3f67ec9d076f
#for rails lower versions 'application.yml' or 'secrets.yml' is used for secret key
- nano <application name>/shared/config/application.yml
  OR
- nano <application name>/shared/config/secrets.yml
- add SECRET_KEY_BASE from your application to this file (or you can generate your own secret key base)
  SECRET_KEY_BASE: "8a2ff74119cb2b8f14a85dd6e213fa24d8540fc34dcaa7ef8a35c246ae452bfa8702767d19086461ac911e1435481c22663fbd65c97f21f6a91b3fce7687ce63"

Server configurations are done. Now configure your rails application.

Rails application setup for capistrano

#configuring capistrano
#add this to gemfile
group :development do
  gem 'capistrano'
  gem 'capistrano3-puma'
  gem 'capistrano-rails', require: false
  gem 'capistrano-bundler', require: false
  gem 'capistrano-rvm'
end
- bundle install

#create configuration files for capistrano
- bundle exec cap install
  #this command will create
  config/deploy.rb
  config/deploy/production.rb
  config/deploy/staging.rb

#add these line to capfile
require 'capistrano/bundler'
require 'capistrano/rvm'
require 'capistrano/rails/assets' # for asset handling add
require 'capistrano/rails/migrations' # for running migrations
require 'capistrano/puma'
install_plugin Capistrano::Puma  # Default puma tasks

#upload puma config  
- cap production puma:config

Edit deploy.rb

lock '3.11.0' #capistrano version

set :application, '<application name>'
set :repo_url, '<git application path>' # Edit this to match your repository
set :branch, :master #use `git rev-parse --abbrev-ref HEAD`.chomp for pick current branch
set :deploy_to, '/home/deploy/<application name>'
set :pty, true
set :linked_files, %w{config/database.yml config/application.yml} #if rails 5.2 & above master.key is used insted of application.yml
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/uploads}
set :keep_releases, 5

Edit the config/deploy/staging.rb

set :rails_env, 'staging'
set :puma_env, fetch(:rack_env, fetch(:rails_env, 'staging'))
server '<staging server public IP address>', user: 'deploy', roles: %w{web app db}

Edit the config/deploy/production.rb

set :rails_env, 'production'
set :puma_env, fetch(:rack_env, fetch(:rails_env, 'production'))
server '<production server public IP address>', user: 'deploy', roles: %w{web app db}

Deploy code to AWS

cap staging deploy #for staging server
cap production deploy #for production server
#login to server & finally restart the nginx
sudo service nginx restart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment