Back-end Engineering Articles

I write and talk about backend stuff like Ruby, Ruby On Rails, Databases, Testing, Architecture / Infrastructure / System Design, Cloud, DevOps, Backgroud Jobs, and more...

Twitter:
@daniel_moralesp

2020-05-01

Add Staging Environment to Any Rails Project

Pre-requisites:

  • * First, I have a Digital Ocean Ubuntu Server
  • * The project has already Capistrano installed and running under just one environment (production)
  • * The server has the credentials of database.yml under /project_name/shared/config/database.yml

Step #1 - Create a new branch and change all from that


$ git branch staging
$ git checkout staging


Step #2 - Have the database.yml clean with just this environments


default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

test:
  <<: *default
  database: db/test.sqlite3

production:
  <<: *default
  database: db/production.sqlite3

staging:
  <<: *default
  database: db/staging.sqlite3

Step #3 - Add Staging Environment with Capistrano


# config/deploy/production

# Replace 127.0.0.1 with your server's IP address!
server '127.0.0.1', user: 'deploy', roles: %w{app db web}

set :branch, 'master'
set :deploy_to, '/home/deploy/project_name_production'
set :stage, :production

# config/deploy/dtaging
# Replace 127.0.0.1 with your server's IP address!
server '127.0.0.1, user: 'deploy', roles: %w{app db web}

set :branch, 'staging'
set :deploy_to, '/home/deploy/staging'
set :stage, :staging

  • Duplicate /config/environments/production and create a file inside and called /config/environments/production with the exact same code inside

Screen Shot 2022-05-30 at 4.39.20 PM.png 67.23 KB

Comment deploy_to line in config/deploy.rb

# config valid for current version and patch releases of Capistrano
lock "~> 3.11.0"

# Default branch is :master
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

# Default deploy_to directory is /var/www/my_app_name
# set :deploy_to, "/var/www/my_app_name"

set :application, "danielmorales"
set :repo_url, "[email protected]:danielmoralesp/danielmorales.git"

# set :deploy_to, '/home/deploy/danielmorales'

append :linked_files, "config/database.yml", "config/master.key", "config/application.yml"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "vendor/bundle", "public/system", "public/uploads"

set :passenger_restart_with_touch, true

  • Gemfile & Capfile keep the same as production

Step #4- Change Nginix config file


The idea now is to change the Ngnix routing like so

  • ssh into the instance
  • cd /etc/nginx/sites-enabled
  • vim default
  • It has to have the line rails_env production; (if not, please add it)

# /etc/nginx/sites-enabled/default

server {
        listen 80;
        listen [::]:80 ipv6only=on;

        server_name 111.111.11.11;
        passenger_enabled on;
        rails_env    production;
        root         /home/deploy/danielmorales/current/public;

        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}

  • Save and exit
  • Inside the same path: sudo touch staging
  • sudo vim staging
  • Now put this inside

# /etc/nginx/sites-enabled/staging

server {
        listen 80;
        listen [::]:80;

        server_name projectname.com staging.projectname.com ;
        passenger_enabled on;
        rails_env    staging;
        root         /home/deploy/staging/current/public;

        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}

  • Save and exit
  • As we can see we changes everything related to production and edit to staging. Alfo in server:name line we put the DNS instead of the Public IP
  • reload Nginx: sudo service nginx reload

Step #5- Make First Deploy


This deploy will fail because we don't have the right folders yet, but the capistrano command will create it for us, so

git add .
git commit -m
git push origin staging
cap staging deploy

The error should look like this

00:03 deploy:check:linked_files
      ERROR linked file /home/deploy/staging/shared/config/database.yml does not exist on 157.245.114.108


Step #6- Create Database & Change database.yml inside DigitalOcean


First we need to create the staging database with the same user as production (deploy user)

  • ssh into the instance and access to postgresql to create the new database

sudo su - postgres
createdb -O deploy projectname_staging
exit

Last command on Step #5 should have created a new folder called staging inside the instance

  • ssh into the server
  • access hereĀ 
    • cd staging/shared/config
  • touch database.yml master.key application.yml
  • sudo vim database.yml
Change the file to have staging environment database connection like this

development:
  adapter: sqlite3
  database: db/development.sqlite3

staging:
  adapter: postgresql
  host: 127.0.0.1
  database: projectname_staging
  username: same_username_as_production
  password: same_password_as_production
  encoding: unicode
  pool: 5

  • sudo vim master.key (copy same key as production)
  • reload Nginx: sudo service nginx reload

Step #7- Add the subdomain


This step depend on where the domain servers are running. In my case I bough the domain under namecheap and deal with it under Cloudflare, so I needed to change everything like this

Screen Shot 2022-05-30 at 4.41.23 PM.png 310.37 KB
Screen Shot 2022-05-30 at 4.41.54 PM.png 392.71 KB

Screen Shot 2022-05-30 at 4.42.00 PM.png 671.66 KB
Screen Shot 2022-05-30 at 4.42.07 PM.png 247.09 KB

Step #8- Re-deploy


Make deploy again, you can change something like this even to check if everything is ok

# to check the environments
<% if Rails.env.production? %>
  - In production
<% elsif Rails.env.staging?  %>
  - In Staging
<% elsif Rails.env.development? %>
  - In Development
<% end %>

$ git add .
$ git commit -m ...
$ git push origin staging
$ cap staging deploy
$ git checkout main
$ git merge staging
$ git push origin main
$ cap production deploy

Step 9 - Test in Browser


Screen Shot 2022-05-30 at 4.46.15 PM.png 265.46 KB
Screen Shot 2022-05-30 at 4.46.24 PM.png 448.63 KB