July 16, 2020

New Site Deployed with Rails & Capistrano

The other day I decided that I would take my new-found enjoyment of Rails and use it to develop my own blog/portfolio website. So, I fired up a DigitalOcean Droplet and got to work. I'll run through how to deploy via Capistrano (https://capistranorb.com/) below.

Deploying with Capistrano

This guide assumes you already have a VPS set up and ready to go.

On our local machine, we can install Capistrano in our Rails app.

First, we will need to add the following gems to our Gemfile:

gem 'capistrano', '~> 3.11'
gem 'capistrano-rails', '~> 1.4'
gem 'capistrano-passenger', '~> 0.2.0'
gem 'capistrano-rbenv', '~> 2.1', '>= 2.1.4'

Once added, we can run the following to install the gems and have Capistrano install its config files:

bundle
cap install STAGES=production

This generates several files for us:

Capfile
config/deploy.rb
config/deploy/production.rb

We're need to edit the Capfile and add the following lines:

require 'capistrano/rails'
require 'capistrano/passenger'
require 'capistrano/rbenv'

set :rbenv_type, :user
set :rbenv_ruby, '2.7.1'

Then we can modify config/deploy.rb to define our application and git repo details.

set :application, "myapp"
set :repo_url, "git@github.com:username/myapp.git"

# Deploy to the user's home directory
set :deploy_to, "/home/deploy/#{fetch :application}"

append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', '.bundle', 'public/system', 'public/uploads'

# Only keep the last 5 releases to save disk space
set :keep_releases, 5

# Optionally, you can symlink your database.yml and/or secrets.yml file from the shared directory during deploy
# This is useful if you don't want to use ENV variables
# append :linked_files, 'config/database.yml', 'config/secrets.yml'
Now we need to modify config/deploy/production.rb to point to our server's IP address for production deployments. Make sure to replace 1.2.3.4 with your server's public IP.

server '1.2.3.4', user: 'deploy', roles: %w{app db web}

Before we can deploy our app to production, we need to SSH into the server one last time and add our environment variables.

ssh deploy@1.2.3.4
mkdir /home/deploy/myapp
nano /home/deploy/myapp/.rbenv-vars

Add any environment variables you need for production to this file.

# For Postgres
DATABASE_URL=postgresql://deploy:PASSWORD@127.0.0.1/myapp

# For MySQL
DATABASE_URL=mysql2://deploy:$omeFancyPassword123@localhost/myapp

RAILS_MASTER_KEY=YOURKEY
SECRET_KEY_BASE=1234567890

STRIPE_PUBLIC_KEY=x
STRIPE_PRIVATE_KEY=y
# etc...

Save this file and these environment variables will be automatically loaded every time you run Ruby commands inside your app's directory on the server.

Using this method, we can have separate env variables for every application we deploy to this server.

Now we can deploy our app to production:

cap production deploy
Open your server's IP in your browser and you should be greeted with your Rails application.

If you see an error, you can SSH into the server and view the log files to see what's wrong.

# To view the Rails logs
nano /home/deploy/myapp/current/log/production.log
# To view the NGINX and Passenger logs
sudo less /var/log/nginx/error.log

Once you find your error (often times a missing environment variable or config for production), you can fix it and restart or redeploy your app.

That's it! If everything goes smoothly, your app should be up and running once the deploy command completes.

tags: ruby capistrano digitalocean rails code