---
title: "Deploy Ruby on Rails 7.0 to Dokku micro PaaS"
description: "Know how to deploy a Ruby Rails 7.0 application to the Dokku micro PaaS with database migrations, Let's Encrypt and more Rails related."
url: "https://qameta.com/posts/deploy-rails-7-0-to-dokku-micro-paas/"
image: "https://qameta.com/posts/deploy-rails-7-0-to-dokku-micro-paas/ruby-on-rails-on-dokku.png"
---

# Deploy Ruby on Rails 7.0 to Dokku micro PaaS

![Ruby on Rails on Dokku](https://qameta.com/posts/deploy-rails-7-0-to-dokku-micro-paas/ruby-on-rails-on-dokku.png)

**This tutorial was tested with Dokku version 0.34.0**

Deploying a [Ruby on Rails](https://rubyonrails.org) application to a
[Dokku](https://dokku.com) 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](https://heroku.com) solved deployment and management on
their [Platform as a Service
(PaaS)](https://en.wikipedia.org/wiki/Platform_as_a_service). 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](https://twitter.com/dhh/status/1671169784694849537?s=20) or
overload of the system hosting too many Heroku instances on an [AWS
EC2](https://aws.amazon.com/en/ec2/) system.

Another thing is the missing support of
[HTTP/2](https://en.wikipedia.org/wiki/HTTP/2), see: [SPDY and HTTP/2 are not
supported at this
time](https://devcenter.heroku.com/articles/http-routing#http-versions-supported).
There are applications, that are slower by several factors without HTTP/2. Also,
Heroku supports Websockets as you can see here: [Heroku
Websocket](https://devcenter.heroku.com/articles/websockets), but it's not a big
of help for almost any website or application using HTTP/2 or newer.

As [PaaS](https://en.wikipedia.org/wiki/Platform_as_a_Service) 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](https://heroku.com) as a
[PaaS](https://en.wikipedia.org/wiki/Platform_as_a_Service), but you can dive in
and check what is going wrong. For me, this is [Dokku](https://dokku.com) 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](https://world.hey.com/dhh/introducing-mrsk-9330a267). Check the
documentation on the project page
[https://kamal-deploy.org](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](https://en.wikipedia.org/wiki/Operating_system) on your server. The one
supported by [Dokku documentation](https://dokku.com/docs/) are listed here:
[Dokku System
Requirements](https://dokku.com/docs/getting-started/installation/). Dependent
on your provider, you can use a [DigitalOcean Droplet
Installation](https://dokku.com/docs/getting-started/install/digitalocean/).


Dependent on your use case and setup check the current Dokku documentation:
[Getting Started with
Dokku](https://dokku.com/docs/getting-started/installation/).

**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`:

```sh
$ 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:

```sh
# 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:

```sh
$ 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](https://dokku.com/docs/community/plugins/) like Let's Encrypt and
others. This is done by running:

```sh
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:

```sh
# 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:

```sh
# 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](https://www.postgresql.org) as a database. You can use
[MySQL](https://www.mysql.com), MySQL forks like [MariaDB](https://mariadb.org),
or [any other supported
database](https://github.com/rails/rails/tree/main/activerecord/lib/active_record/connection_adapters).

You can use these [Dokku database
plugins](https://dokku.com/docs/community/plugins/):

* [PostgreSQL](https://github.com/dokku/dokku-postgres)
* [MariaDB](https://github.com/dokku/dokku-mariadb)
* [MySQL](https://github.com/dokku/dokku-mysql)
* [MongoDB](https://github.com/dokku/dokku-mongo)

... and many more. See the [list of Dokku-supported and community-supported
plugins](https://dokku.com/docs/community/plugins/).

### PostgreSQL Dokku database setup

As an example, I will create a PostgreSQL Database called `rails7-example-db`
through the [PostgreSQL Dokku plugin](https://github.com/dokku/dokku-postgres)
and link it to my `rails7-example` application.

```sh
# 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):

```sh
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`:

```txt
# 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](https://github.com/puma/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:

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

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

```json
{
  "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](https://guides.rubyonrails.org/active_record_migrations.html) on
your application start.

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

```txt
# 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:

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

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

```sh
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:

```sh
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](https://github.com/dokku/dokku-letsencrypt) for your Dokku instance and
set a global email used for Let's Encrypt:

```sh
# 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](https://github.com/dokku/dokku-letsencrypt) for your application
`rails7-example` by running:

```sh
dokku letsencrypt:enable rails7-example
```

Running this command will take some time, as [Let's
Encrypt](https://letsencrypt.org) 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:

```sh
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:

```sh
# 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](https://github.com/sidekiq/sidekiq) or
[Resque](https://github.com/resque/resque), you have to install the [Dokku Redis
Plugin](https://github.com/dokku/dokku-redis) and set up your scheduler through
`Procfile`.

### Setup Redis through Dokku Plugin

Install the [Dokku Redis Plugin](https://github.com/dokku/dokku-redis) and add
it to your application `rails7-example`:

```sh
# 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](https://github.com/resque/resque#redis) or
[Sidekiq](https://github.com/sidekiq/sidekiq) look for the
[Redis](https://redis.io) instance they need.

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

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

For the Resque Scheduler, this is pretty similar:

```sh
# 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:

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

Afterward check the status by running:

```sh
dokku ps:inspect rails7-example
```

Dokku has great [documentation](https://dokku.com/docs/). Check the [Process
Management](https://dokku.com/docs/processes/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](https://dokku.com) you have a great platform to do all the tasks, you
are familiar with by using [Heroku](https://heroku.com) with more control of the
application and without many of the disadvantages
[Heroku](https://www.heroku.com) has for you.
