Deploy Ruby on Rails 7.0 to Dokku micro PaaS

Reading time: 10 minutes

Dokku Website

This tutorial was tested with Dokku version 0.34.0

Deploying a Ruby on Rails application to a Dokku instance is pretty forward. There are only a few things you have to consider. In this guide, I will tell you, what might be the things and how to solve them. I was missing a complete guide with explanations aligned to the deployment of a default Ruby on Rails application.

Motivation

I love the way Heroku solved deployment and management on their Platform as a Service (PaaS). What I don’t like is the overall slowness and the very limited amount of memory Heroku provides resulting in a very fast overload of an instance by even low increase of traffic. It may be related to low AWS performance or overload of the system hosting too many Heroku instances on an AWS EC2 system.

Another thing is the missing support of HTTP/2, see: SPDY and HTTP/2 are not supported at this time. There are applications, that are slower by several factors without HTTP/2. Also, Heroku supports Websockets as you can see here: Heroku Websocket, but it’s not a big of help for almost any website or application using HTTP/2 or newer.

As PaaS user, you may don’t want to see every detail of the system like CPUs, RAM, and even database details. But if things start to slow down or break at some point, it gets messy, because you or your team are the ones who are responsible for the running application, even if Heroku is proving the platform to work smoothly. For me, it failed several times and failed hard.

Self hosted PaaS - Dokku

Let’s think of a micro Heroku as a PaaS, but you can dive in and check what is going wrong. For me, this is Dokku for smaller use cases, where you don’t need many servers to run a web application.

If you need a multi-server setup, which is better to scale for bigger applications, maybe check Kamal Deploy by DHH. Check the documentation on the project page https://kamal-deploy.org.

Dependent on your requirements you can start with Dokku and switch later to a multi server solution with many servers or move to Heroku.

Dokku Basic Setup

First of all, you need to install an operating system on your server. The one supported by Dokku documentation are listed here: Dokku System Requirements. Dependent on your provider, you can use a DigitalOcean Droplet Installation.

Dependent on your use case and setup check the current Dokku documentation: Getting Started with Dokku.

ATTENTION: Dokkus default setup doesn’t use any remote API or CLI to control your instances as Heroku does. You have to run all dokku commands on your remote machine, where you have installed Dokku (in this tutorial I call the machine dokku.example.com).

Add a swap space to virtual machine

Most virtual machines don’t have a swap space, which we consider as essential to stop crashes due to short memory (RAM) limit.

Check you setup first by running free -m and look work Swap:

$ free -m
               total        used        free      shared  buff/cache   available
Mem:            1915         794         107          17        1014         912

The setup is of a swap space is pretty simple:

# allocate a file with 2GB space
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

if you check again using free -m you will see a swap space:

$ free -m
               total        used        free      shared  buff/cache   available
Mem:            1915         794         107          17        1014         912
Swap:           2047           0        2047

HINT: Dependent on your system setup you can have a local partition or a special mounted space, which you may use for the swap file. A machine built it raid array or a SSD drive are great for swap.

Prepare Dokku for Ruby on Rails

Information: You don’t need to run all remote commands using sudo or as root if your user is allowed to use sudo with or without a password. Dokku will determine the context and request permissions running sudo by itself.

Tu run a Ruby on Rails Application, you need to have the right plugins installed like Let’s Encrypt and others. This is done by running:

dokku plugin:install-dependencies --core

This is part of the installation instructions and you may have done it already.

Create your application in Dokku

Set up your app in your Dokku instance before you add the required database plugin. You will need instructions on how to link your database to your application, which is written down in the plugins manual.

We will call the app rails7-example here and refer to it throughout the whole tutorial:

# create an app in dokku
dokku apps:create rails7-sample

After creating the application, we need to set Ruby on Rails specific environment variables and dependent on used gems their specific environment variables.

Ruby on Rails specific configuration

Set the Ruby on Rails specific environment variables through dokku configuration command:

# Set the Ruby on Rails Environment
dokku config:set rails7-sample RAILS_ENV=production
# Set your Ruby on Rails Master Key to decrypt the encrypted credentials file
dokku config:set rails7-sample RAILS_MASTER_KEY=your_rails_master_key

Install the Dokku Database Plugin

I prefer PostgreSQL as a database. You can use MySQL, MySQL forks like MariaDB, or any other supported database.

You can use these Dokku database plugins:

… and many more. See the list of Dokku-supported and community-supported plugins.

PostgreSQL Dokku database setup

As an example, I will create a PostgreSQL Database called rails7-example-db through the PostgreSQL Dokku plugin and link it to my rails7-example application.

# Install PosgreSQL Dokku Plugin
dokku plugin:install https://github.com/dokku/dokku-postgres.git
# Create a database
dokku postgres:create rails7-example-db
# Link the PostgreSQL database to your application
dokku postgres:link rails7-example-db rails7-example

The Link command will set the DATABASE_URL environment variable to the database for the application (the same as Heroku does with Postgres).

If you use another database, take a look at the documentation of the corresponding Dokku plugin. It should be pretty similar and easy to set up.

Prepare your app for deployment

All these steps should be done and committed through git in your repository containing your Ruby on Rails application.

Define platform for C-extensions

If you have developed your Ruby on Rails application on a newer Mac running an ARM processor (Apple called them M1, M2, etc.) and your deployment is on an AMD64 (x86_64) Linux environment, you have to add it to your Gemfile or Gems with C-extensions will fail to build. Run this command and commit the change to your project (this is the same for Heroku):

bundle lock --add-platform x86_64-linux
git add Gemfile*
git commit -m "Added AMD64 (x86_64) Linux support"

Define application server

As on Heroku, you have to define, how to start your application. You can define it using a Procfile:

# Procfile starting a service web using Puma as an application server
web: bundle exec puma -C config/puma.rb

In this example we use Puma as application server.

Define Node.js version

If you are using yarn for your assets, you have to define the Node.js version and yarn version to be used in your package.json file:

{
  "engines": {
    "node": "20.x",
    "yarn": "1.22.19"
  }
}

If you use npm instead of yarn, define it this way in your package.json file:

{
  "engines": {
    "node": "20.x",
    "npm": "10.x"
  }
}

Attention: If you have some kind of CI/CD pipeline, you should use the same Node.js version or your CI/CD may complain, that the wrong version of Node.js is used.

Running migrations

Dependent on your use case, you can or even should run database migrations on your application start.

The most simple solution is to add an entry to your Procfile before starting the application server:

# run migrations before starting the web server
release: bundle exec rails db:migrate
# Procfile starting a service web using Puma as application server
web: bundle exec puma -C config/puma.rb

As some applications may be deployed to different environments and servers, I prefer to run the migrations through an app.json file, which can be aligned to every environment (like deployment to Heroku and Dokku) from the same repository. A basic app.json file for Dokku only looks like this:

{
  "scripts": {
    "dokku": {
      "postdeploy": "bundle exec rails db:migrate"
    }
  }
}

If you prefer to run migrations by hand, check this command:

dokku run rails7-example bundle exec rake db:migrate

Setup Domain and secure connection using HTTPS

To secure the connection between your Dokku proxy server (nginx by default) and the client’s browser/application using your ruby on rails application, you have to define the domain rails7example.com for your application:

dokku domains:set rails7-example rails7example.com

Use Let’s Encrypt for SSL/TLS Certificates

You have to install the Let’s Encrypt Dokku plugin for your Dokku instance and set a global email used for Let’s Encrypt:

# Install the Let's Encrypt plugin from the official repository
dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
# Set a global email used by the Let's Encrypt plugin for certificates
dokku letsencrypt:set --global email your-email@your-domain.com

Now enable the Let’s Encrypt Dokku plugin for your application rails7-example by running:

dokku letsencrypt:enable rails7-example

Running this command will take some time, as Let’s Encrypt checks your domain setup and sign your request if valid. If it fails, check your A and AAAA records for the domain. They may be wrong.

Let’s Encrypt certificates are valid for a short period of time. The best thing is to setup cron for auto-renewal by running it as a cron job:

dokku letsencrypt:cron-job --add

ATTENTION: If you check for cron jobs managed by Dokku, you won’t find Let’s Encrypt there. It is managed through the plugin itself.

Deploy your application

To deploy your Ruby on Rails application called rails7-example to your Dokku instance (as an example called dokku.example.com) from your development machine run these commands:

# Add your Dokku instance as remote repository for deployment
git remote add dokku dokku@dokku.example.com:rails7-exameple
# Deploy by pushing your main branch to the remote repository Dokku within the
# master branch
git push dokku main:master

If everything worked, your application should have been deployed and should be accessible under your select domain e.g. rails7example.com.

Additional services through plugins

If your application requires a job scheduler like Sidekiq or Resque, you have to install the Dokku Redis Plugin and set up your scheduler through Procfile.

Setup Redis through Dokku Plugin

Install the Dokku Redis Plugin and add it to your application rails7-example:

# Install Redis through Dokku
sudo dokku plugin:install https://github.com/dokku/dokku-redis.git redis
# Create redis instace for your application
dokku redis:create rails7-example-redis
# Add redis to your application and promote it through REDIS_URL
dokku redis:link rails7-example-redis rails7-example

The link command will provide a REDIS_URL with all the data Ruby on Rails will need to use it. Now you need to check how Resque or Sidekiq look for the Redis instance they need.

Now you need to setup a worker to be launched on startup in you Procfile for Sidekiq:

# Add a worker to your Procfile for Sidekiq
worker: bundle exec sidekiq -C config/sidekiq.yml

For the Resque Scheduler, this is pretty similar:

# Add worker to your Procfile for Sidekiq
worker: env QUEUE=* bundle exec rake resque:work

Now commit the changes and deploy your application.

If Dokku will not spawn your worker instances by default, you can enable the worker scaling by running:

dokku ps:scale rails7-example web=1 worker=1

Afterward check the status by running:

dokku ps:inspect rails7-example

Dokku has great documentation. Check the Process Management documentation for more details how to manage and to scale your processes for your needs.

Summary

Dependent on the use case of your application, it is enough to run a single hardware or virtual server for your application. By using Dokku you have a great platform to do all the tasks, you are familiar with by using Heroku with more control of the application and without many of the disadvantages Heroku has for you.


Newsletter


See Also


Tags