Deploying Ruby on Rails To A New Digital Ocean or Linode VPS
Update April 6 2018 –– I would now recommend Nanobox for this type of deployment.
I’ve been looking recently for a better way of deploying new Rails apps to VPS – better that is than how I’ve done this on a few occasions in the past: apt-getting the whole darned thing piece by piece using Google and Stack Overflow to comb through ideas.
Past Experience With Webfaction
Previously, I used WebFaction for small business clients, but I have been finding it increasingly unreliable, and for larger clients, it feels like it may not be a solid solution.
Past Experience With Heroku
Heroku is brilliant, but I set it up for a large client recently and I’m personally finding the cost shocking. It’s been an ongoing concern of limited resources and Heroku restrictions that has forced us to scale up, which increases the cost that much more.
Past Experience With Linode
I manually set up a few Linode machines and combined with Monit, they have been kicking ass so far for years without hassle.
Searching for alternatives, I stumbled on this great talk, Deploying Rails Is Easier Than It Looks, which I missed at RailsConf 2014. I later read through Ben’s great tutorials on server setup and Capistrano deployment, and then checked out his code templates for server template and Capistrano template, and bought his book, Reliably Deploying Rails Applications.
My Notes Based On Talking Loudly
I found I had to do some tweaking and debugging to go from absolutely nothing to a deployed Rails application, but I’m hoping the hours I’ve put in will more than pay off in the long run.
These are my notes, based on Ben’s various tutorials, templates and book – from which I am able to get painlessly through the procedure of server setup and app deployment circa September 2014 on Digital Ocean.
Note: you may need to setup rbenv locally
First, I followed Ben’s steps of cloning his template and defining the deploy user credentials:
Initial Server Template Setup
git clone email@example.com:TalkingQuickly/rails-server-template.git cd rails-server-template bundle install cd data_bags/users && cp deploy.json.example deploy.json
Add deploy user password and your ssh key to deploy.json
mkdir cookbooks bundle exec berks vendor cookbooks
ssh-copy-id -i /pathToYourPrivateKey root@xxx # copy up your ssh to bundle exec knife solo prepare root@yourip # prepare remote server for chef install bundle exec knife solo cook root@yourip # do chef install on remote server
Create new Rails app, push it to repo
rails new myapp -D postgres # create new rails app cd myapp # go to rails app git init # start a git repo git add . # add new rails app git commit -m 'init' # initial git commit
Now could be a good time to create a Bitbucket or Github etc repo, add existing as per provider instructions
Add Capistrano template into the mix
Add Capistrano template to the rails app: https://github.com/gordonbisnor/capistrano-3-rails-template
group :development do gem 'capistrano', '>= 3.3.5' gem 'capistrano-rbenv' gem 'capistrano-bundler' # for capistrano/bundler gem 'capistrano-rails' end gem 'unicorn'
Capistrano initial setup
cap production deploy:setup_config # setup remote for Capistrano deployment ssh root@myServerIp # ssh into remote machine
On Remote Machine:
cd /home/deploy/apps/myapp/shared/config # go to app config folder cp database.example.yml database.yml # copy to real database.yml – fill in user, pass and host: localhost chown deploy database.yml # if you’re logged in as root, cp file will mean that root owns file, will cause permission error cp secrets.example.yml secrets.yml # copy secrets file, and fill in secret key base chown deploy secrets.yml su postgres # change session owner to postgres psql # open postgres client
Create database on remote server:
CREATE DATABASE xxx; CREATE USER xxx WITH PASSWORD 'xxx'; GRANT ALL ON DATABASE xxx to xxx; \q # exit out of postgres client exit # to get out of postgres su session
Add database credentials to database.yml, and setup secrets.yml, as well as any other config files
logout # logout of server
On Development Machine - Deploy
cap production deploy
You should now be able to visit your server’s IP address and see your site. I added a root path to routes.rb, a welcome controller and a welcome/index template to test.
For debugging I found I had to refer to /home/deploy/apps/shared/config/logs/unicorn.log a bit – I was turning up with a blank site, this happened a few times related to permissions issues and missing secrets.yml file. Hence my fork of Ben’s Github repo that addressed this. Anyway: that could come in handy for debugging purposes, along with Capistrano output, etc.
Configure pg backups for your node to backup to S3. In the Amazon control panel, specify a lifecycle rule to delete backups after 7 days for example, the rule:
Gemfile gem ‘capistrano-cookbook’, require: false, group: :development gem ‘capistrano-sidekiq’, ‘>= 0.5.2’
require 'capistrano/sidekiq' require 'capistrano/sidekiq/monit” require 'capistrano/cookbook/monit'
set :sidekiq_monit_conf_dir, '/etc/monit/conf.d'
bundle exec cap production sidekiq:monit:config bundle exec cap production monit:reload bundle exec cap production deploy
I am available for Ruby on Rails consulting work – get in touch to learn more.