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.
Talking Loudly
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 git@github.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
Install cookbooks
mkdir cookbooks
bundle exec berks vendor cookbooks
Prepare server
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
Gems:
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.
Backups
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:
db/backups/
Sidekiq
Gemfile gem ‘capistrano-cookbook’, require: false, group: :development gem ‘capistrano-sidekiq’, ‘>= 0.5.2’
Capfile
require 'capistrano/sidekiq'
require 'capistrano/sidekiq/monit”
require 'capistrano/cookbook/monit'
config/deploy.rb
set :sidekiq_monit_conf_dir, '/etc/monit/conf.d'
command line
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.