Deploying Rails From Scratch

In this tutorial we will use tomo to deploy a sample Rails project to a virtual private server (VPS). These instructions use DigitalOcean as the hosting provider, but any provider that offers an Ubuntu 20.04 or 22.04 LTS VPS should work in a similar way. Here are the steps involved (step 1 is the only part that is DigitalOcean-specific):

  1. Create an Ubuntu VPS
  2. Install necessary apt packages
  3. Set up a deployer user
  4. Configure tomo
  5. Run tomo setup
  6. Run tomo deploy

This is a basic tutorial that skips over DNS, TLS, load balancing, PostgreSQL, etc. If you have suggestions for expanding this guide, consider opening an issue or pull request on GitHub. Thanks for reading!

Create an Ubuntu VPS

Log into DigitalOcean and create a “Droplet” (aka a VPS). If this is your first time using DigitalOcean, check out their Droplet QuickStart guide for an introduction to the service.

When creating the Droplet, make sure to choose Ubuntu 20.04 or 22.04 (LTS) x64:

Ubuntu 20.04 LTS

And use SSH keys for authentication (tomo does not work with password authentication):

SSH Authentication

And select a Droplet size with at least 1GB RAM, or Ruby may fail to compile:

Smallest Viable Droplet

Once the Droplet is created, confirm that you are able to connect to it (substitute IPADDR with the IP address provided in the DigitalOcean control panel for the new Droplet):

# Run on your local machine
$ ssh -o PasswordAuthentication=no root@IPADDR echo "authenticated as root!"
authenticated as root!

You may need to type yes when prompted to trust the host fingerprint.

Install necessary apt packages

Rails requires certain operating system packages in order to build Ruby and install various gems that have native extensions. Connect to the VPS as root and install the following:

# Run these commands as root on the VPS
apt-get -y update
apt-get -y install autoconf \
                   bison \
                   build-essential \
                   curl \
                   git-core \
                   libdb-dev \
                   libffi-dev \
                   libgdbm-dev \
                   libgdbm6 \
                   libgmp-dev \
                   libncurses5-dev \
                   libreadline6-dev \
                   libsqlite3-dev \
                   libssl-dev \
                   libyaml-dev \
                   locales \
                   patch \
                   pkg-config \
                   rustc \
                   uuid-dev \
                   zlib1g-dev \
                   tzdata
locale-gen en_US.UTF-8

It may take a minute or two for all the packages to install.

Set up a deployer user

Running a Rails app as root is a security risk; we need to create a non-privileged user for this purpose. Run the following script to create a deployer user that:

  • has access to write to a /var/www directory, which is the default location where tomo will deploy our app; and
  • can “linger”, i.e. run long-running processes like the puma web server
# Run these commands as root on the VPS
adduser --disabled-password deployer < /dev/null
mkdir -p /home/deployer/.ssh
cp /root/.ssh/authorized_keys /home/deployer/.ssh
chown -R deployer:deployer /home/deployer/.ssh
chmod 600 /home/deployer/.ssh/authorized_keys
mkdir -p /var/www
chown deployer:deployer /var/www
loginctl enable-linger deployer

For convenience, the deployer user will accept the same SSH key that you are already using to authenticate when connecting as root. Test that it works:

# Run on your local machine
$ ssh -o PasswordAuthentication=no deployer@IPADDR echo "authenticated as deployer!"
authenticated as deployer!

Configure tomo

We will be deploying this basic Rails app. It is a standard Rails app generated by rails new, with the exception that force_ssl has been set to false for the production environment. This will allow us to deploy the app without having to set up HTTPS, which is outside the scope of this tutorial.

Clone the repository to get started:

# Run on your local machine
$ git clone https://github.com/mattbrictson/rails-new

Inside the rails-new directory, install tomo and run tomo init. This will set up a deploy configuration with a good set of defaults:

# Run on your local machine
$ cd rails-new

$ gem install tomo
Fetching tomo-1.11.0.gem
Successfully installed tomo-1.11.0
1 gem installed

$ tomo init
✔ Created .tomo/config.rb

The .tomo/config.rb configuration is ready right out of the box. All you will need to change is the host line, and be sure to replace IPADDR with the IP address of your VPS:

# Modify the 'host' line of .tomo/config.rb
host "deployer@IPADDR"

Run tomo setup

Tomo comes with a setup command that will prepare your VPS for its first deployment. This does things like install Node, Yarn, and Ruby. It also sets up some important environment variables. Just run:

# Run on your local machine
$ tomo setup

You will be asked to specify a value for the DATABASE_URL environment variable. Tomo will store this value on the VPS so that you only have to provide it once. Provide this value when prompted: sqlite3:/var/www/rails-new/shared/production.sqlite3.

Note that tomo setup compiles Ruby from source, which will take several minutes.

Run tomo deploy

Once setup completes, your VPS is ready to go. Deploying is now just a matter of running tomo deploy:

# Run on your local machine
$ tomo deploy

When the deploy completes, the Rails app will be accessible on port 3000 of your VPS: http://IPADDR:3000.

Congratulations!