Skip to content

Instantly share code, notes, and snippets.

@DRBragg
Created September 14, 2018 20:38
Show Gist options
  • Save DRBragg/ca6331d5b94e338d956d1af559e5c74a to your computer and use it in GitHub Desktop.
Save DRBragg/ca6331d5b94e338d956d1af559e5c74a to your computer and use it in GitHub Desktop.
DO setup for RoR app

Setting up Digital Ocean Server for Deployment

  • Create a droplet

    • Choose Ubuntu as your distribution (16.04.4 x64)
    • Choose the size of your droplet (min 1GB and 1CPU)
    • Choose New York 1 or 3 for your datacenter
    • Optional:
      • Add SSH keys now (can also do this later)
      • Rename the hostname (generally to something that makes sense)
  • Once the droplet is created an email is sent with the login credentials

  • Use the provided credentials to SSH into the new droplet

  • It is best practice to make a new user to manage deployments rather that using root

    • $ sudo adduser deploy
    • $ sudo adduser deploy sudo
    • $ su deploy
  • If you did not provide SSH keys when you created the droplet do that now.

    This is done on your computer NOT on the server

    • If you do not already have ssh-copy-id
    • Run $ brew install ssh-copy-id
    • Run $ ssh-copy-id deploy@SERVERIP where SERVERIP is the IP address of your droplet
  • SSH back into the server as the deploy user

Run the following on the server as deploy

  • First get the basic dependencies

    • $ curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -

    • $ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

    • $ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

    • $ sudo apt-get update

    • $ 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 nodejs yarn

  • Then install rbenv (for managing our ruby versions)

    • $ cd

    • $ git clone https://github.com/rbenv/rbenv.git ~/.rbenv

    • $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc

    • $ echo 'eval "$(rbenv init -)"' >> ~/.bashrc

    • $ exec $SHELL

    • $ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

    • $ echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc

    • $ exec $SHELL

  • Finally install ruby

    • $ rbenv install 2.4.1 -- or whatever version of ruby your application is running at the time

    • $ rbenv global 2.4.1 -- or whatever you just installed

    • $ ruby -v -- to verify the correct version is installed and set

    • $ gem install bundler

    • $ rbenv rehash

Setup Nginx with Passenger

This will actually run our 'server' and serve (no pun intended) our app

  • $ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7

  • $ sudo apt-get install -y apt-transport-https ca-certificates

  • $ sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger xenial main > /etc/apt/sources.list.d/passenger.list'

  • $ sudo apt-get update

  • $ sudo apt-get install -y nginx-extras passenger

Check to make sure everything you just did worked correctly

Run $ sudo service nginx start on the server and then visit the droplets IP address in the browser

Configure Nginx and Passenger
  • $ sudo vim /etc/nginx/nginx.conf

    • Find the following lines of code and uncomment include /etc/nginx/passenger.conf:
     ##
     # Phusion Passenger
     ##
     # Uncomment it if you installed ruby-passenger or ruby-passenger-enterprise
     ##
    
     include /etc/nginx/passenger.conf;
    
    • Save and close (:wq)
  • $ sudo vim /etc/nginx/passenger.conf

    • Change the passenger_ruby line to point to rbenv:
      • passenger_ruby /home/deploy/.rbenv/shims/ruby;
    • Save and close (:wq)
Once this is all completed restart the Nginx Server
  • $ sudo service nginx restart

Environmental Variables

  • Ensure you are in the top most level of the deploy user section
    • Run $ cd ~
  • $ git clone https://github.com/rbenv/rbenv-vars.git $(rbenv root)/plugins/rbenv-vars
  • $ vim .rbenv-vars
  • Add your ENV variables to the file

PostgreSQL

  • Run $ sudo apt-get install postgresql postgresql-contrib libpq-dev
  • Set up the postgres user (also named "deploy" but different from our linux user named "deploy") and DB
    • $ sudo su - postgres
    • $ createuser --pwprompt deploy -- make note of the password you choose
    • $ createdb -O deploy APP_NAME_production -- where APP_NAME is the name of the application
    • $ exit

Deploying

Fist we need to configure our repo's bucket to be able to talk to our server. Since we deploy directly from the repo rather that our local machine.

  • While SSHed in our server, enter ssh-keygen at the command line.
  • Follow the prompts to set up a new key. A passphase is not needed in this case.
  • Once the server has generated a new key run cat ~/.ssh/id_rsa.pub and copy the returned key
  • Add the key to the App's repo

When this repo is cloned Capistrano should already be setup but we'll need to change some config files for each instance.

  • In config/deploy.rb change the following lines, updating them to the name and repo of the current application:
    set :application, "APP_NAME"
    set :repo_url, "YOUR_REPOS_URL" -- HTTPS or SSH

    set :deploy_to, "/home/deploy/APP_NAME"
  
  • In config/deploy/production.rb change the IP address of the server to the IP of the new droplet
    server 'IP_ADDRESS', user: 'deploy', roles: %w{app db web}
  
  • You can then use the command cap production deploy to deploy new versions of the app
  • The first time you try this it will fail and throw an error, but we're almost there.

Last steps

SSH back into the server as deploy and create 2 files

  • /home/deploy/APP_NAME/shared/config/database.yml
    • In this file add the following:
      production:
        adapter: postgresql
        host: 127.0.0.1
        database: APP_NAME_production
        username: deploy
        password: YOUR_POSTGRES_PASSWORD (NOT YOUR LINUX PASSWORD)
        encoding: unicode
        pool: 5
    
  • /home/deploy/APP_NAME/shared/config/secrets.yml
    • In this file add the following:
    production:
      secret_key_base: YOUR_SECRET_KEY
    

Run $ sudo visudo -f /etc/sudoers.d/nginx_overrides and add the following to the file:

  # Nginx Commands
  Cmnd_Alias NGINX_RESTART = /usr/sbin/service nginx restart
  Cmnd_Alias NGINX_RELOAD  = /usr/sbin/service nginx reload

  # No-Password Commands
  deploy ALL=NOPASSWD: NGINX_RESTART, NGINX_RELOAD

Updating the URL

Last this to do on the server is to tell Nginx to respond with the app

  • Run sudo ln -s /etc/nginx/sites-available/THE_URL_YOU_WANT_HERE.com /etc/nginx/sites-enabled/
  • Then sudo vim /etc/nginx/sites-enabled/THE_URL_YOU_WANT_HERE.com and replace the files contents with:
server {
      listen 80;
      listen [::]:80 ipv6only=on;

      server_name THE_URL_YOU_WANT_HERE.com;
      passenger_enabled on;
      rails_env    production;
      root         /home/deploy/APP_NAME/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;
      }
}
  • Back on your local machine run $ cap production deploy once more and then you should be in business

  • If you are still seeing the default Nginx page, run $ cap production server:restart

Backups (Experimental)

  • SSH into the server as deploy
  • Run $ gem install backup -v5.0.0.beta.1
  • Run backup generate:model --trigger production_backup
  • Edit the automatically generated file $ vim ~/Backup/models/production_backup.rb and replace its contents with:
# encoding: utf-8

##
# Backup Generated: production_backup
# Once configured, you can run the backup with the following command:
#
# $ backup perform -t production_backup [-c <path_to_configuration_file>]
#
# For more information about Backup's components, see the documentation at:
# http://backup.github.io/backup
#
Model.new(:production_backup, 'Description for production_backup') do
    split_into_chunks_of 250
    compress_with Gzip

    database PostgreSQL do |db|
        db.name               = "APP_NAME_production"
        db.username           = "deploy"
        db.password           = "YOUR_POSTGRES_PASSWORD"
        db.host               = "127.0.0.1"
        db.port               = 5432
    end

    archive :app_archive do |archive|
        archive.use_sudo
        archive.add '/home/deploy/APP_NAME/'
    end

    store_with S3 do |s3|
        s3.access_key_id = "AWS_ACCESS_KEY_ID"
        s3.secret_access_key = "AWS_SECRET_ACCESS_KEY"
        s3.region = "AWS_REGION" (default is us-west-2)
        s3.bucket = "AWS_BUCKET"
        s3.path = "/production/database"
    end
end
  • Test the back up by running $ backup perform -t production_backup

  • Set up a cronjob to run as often as you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment