For me, it’s been always cumbersome to host a Rails side project or personal application. Sure, Heroku is straightforward but it’s not as cheap as I would like it to be. And I don’t like the uptime limitation their free plan has. I have been making my way through Dokku and Capistrano. Luckily, a new door opened when Kamal was launched by DHH recently.

In this post, I am not getting into how Kamal works and the benefits of using it. DHH has created this fantastic introduction video for that.

Kamal is capable to deploy applications on multiple servers as well as a single server. In this post, I will describe how we can deploy a Rails application and Postgresql on a single VPS.

First of all, install and init Kamal on your local machine with instructions on the README.

The key to the single server setup is to use the same hosts for the web as well as accessories. Here is what the deploy.yml file looks like for that setup:

service: my-app
image: user/my-app

servers:
  web:
    - 134.209.111.91

registry:
  username: tannakartikey
  password:
    - KAMAL_REGISTRY_PASSWORD

env:
  clear:
    DB_HOST: 134.209.111.91
  secret:
    - RAILS_MASTER_KEY
    - POSTGRES_PASSWORD

accessories:
  db:
    image: postgres:15
    host: 134.209.111.91
    port: 5432
    env:
      clear:
        POSTGRES_USER: 'my_app'
        POSTGRES_DB: 'my_app_production'
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data

I am using the default Dockerfile that is generated with Rails 7.1. Create and place the Dockerfile in your root directory if it does not exist already. You also need to create a .env file in the root of the repository and also need to make minor changes in your config/database.yml file.

I have created this sample repository that has all the code described in this post. This commit holds all the Kamal setup-related changes.

Be sure NOT to include your .env file in Git or your Dockerfile. If you are using Docker Hub or any other registry, make sure to make the image private because it holds a copy of the application code.

Next, we need to set up the server since we are deploying to the server for the first time. We can do it with:

bin/kamal setup

The setup command will set up all the accessories and deploy the app on the server.

That’s it! You should have a running Rails app on the server which is connected to Postgresql on the same server. For subsequent deploy you can use kamal deploy or kamal redeploy based on your needs.

I have been using the USD4 droplet on DigitalOcean. If you are using a similar configuration I would recommend creating a swap partition on the server. I am assuming that if you are doing this, you are not expecting loads of traffic on day one. But without a swap partition, some simple operations like migrating the database may also fail.

It can also be possible to host the same code multiple times for different environments i.e. staging, production etc. For that, the “role” and “destination” functionality of Kamal can be used. I might cover that in a separate post.