Ruby on Rails has always been at the forefront of developer productivity, and building robust, highly interactive web applications has never been easier. Rails has been accurately described as the one-person framework. However, building your app is only half the battle. The other half is publishing it for others to use. Unfortunately, being able to deploy your application has always been an afterthought for most developers. The "one-person framework" doesn't carry through when it comes to deployment and operations unless you have specialized knowledge of building out infrastructure or pay others large sums of money to do it for you—until now. With the release of Kamal, the "one-person framework" idea completes the stack from end to end, allowing a single developer to do more with fewer resources.

Kamal is a new deployment tool created by the folks at 37Signals. It allows you to codify the deployment process into a single file and abstract many complicated bits that most applications don't need to worry about. It does this by using a combination of software like Docker containers and Traefik. Out of the box, along with Rails, you get a complete package that will get you production-ready in no time.

How it works

Kamal runs your web application in a Docker container on a server. It then uses a web server called Traefik to handle the network traffic between the Docker container and the internet.

The neat thing is that whenever you deploy a new version of your application, Kamal will do the following:

  1. Build a new version of a Docker image.
  2. Start a new container of that image.
  3. Ensure that the new container is healthy.
  4. Tell Traefik to start directing traffic to the new container.
  5. Stop the old container.

The benefit is that you can theoretically have zero downtime and blue/green deploys.

Kamal can also help scale your application horizontally by deploying your containers to multiple servers—but you'll need to load balance the servers yourself.

Setup

Install the Kamal gem on your local computer:

gem install kamal

Then, in your Rails application, initialize the setup:

kamal init

The kamal init command will create two files. config/deploy.yml contains everything Kamal will use to deploy your app, and .env has secret environment variables used to configure your app (and should not get committed to your repo).

Acquire a VPS

Before configuring Kamal, let's discuss where we'll host our web app. There are lots of great options to choose from. An excellent cost-effective choice is a Virtual Private Server (VPS). A VPS is cost-effective because you are essentially sharing hardware with other customers. Although completely isolated from each other access-wise, you may have to contend with others for resources, which means some CPU bandwidth, memory, and storage limitations. A VPS should be fine for most applications, especially for this tutorial.

When choosing a VPS hosting provider, find one with a data center closest to you for faster response times. When selecting the level of resources, at a minimum, I'd recommend something with at least 1GB of memory for Rails applications. Also, choose a Debian-based Linux for the OS, as it's a popular choice, and it will be easy to find help if you run into trouble. Make sure that you have SSH access to the VPS. After creating your VPS, make a note of the published IP Address.

Acquire a domain name

If you plan to enable TLS/SSL for your application, you'll need to register a domain name and configure the DNS with a CNAME record to point to the IP address of your VPS.

Docker image registry

Kamal uses Docker containers for deployment. It takes your Dockerfile and builds an image that will be used on your server. This image must be uploaded to a "registry." However, there are many free options to choose from, such as DockerHub, GitHub, or DigitalOcean. You'll need to sign up for one of these services and note the username and password you'll use to log in (or access tokens if applicable).

Configuration

Now that you have your VPS and registry login credentials, we can start configuring the deployment. At a minimum, your config/deploy.yml file should look like this:

service: my-app
image: <your-registry-username>/my-app
servers:
  web:
    hosts:
      - <your vps ip address>
registry:
  username:
    - <your-registry-username>
  password:
    - KAMAL_REGISTRY_PASSWORD

# If you use another service like DigitalOcean:
# registry:
#   server: registry.digitalocean.com
#   username:
#     - <your-registry-username>
#   password:
#     - KAMAL_REGISTRY_PASSWORD

env:
  secret:
    - RAILS_MASTER_KEY

Fill in the required values as needed. Two environment variables will need our attention: KAMAL_REGISTRY_PASSWORD and RAILS_MASTER_KEY. These get populated by the .env file upon deployment. Edit your .env file to look something like this:

KAMAL_REGISTRY_PASSWORD=<your-registry-password-or-token>
RAILS_MASTER_KEY=<your-rails-production.key-value>

These values can be safely stored here as they shouldn't be committed to your repo, and they get securely transferred to the VPS when deployed. The RAILS_MASTER_KEY can be found in config/credentials/production.key. If it doesn't exist, you can create it by running the following:

rails credentials:edit --environment=production

Deployment

The first thing you'll want to do is run the server bootstrap command:

kamal server bootstrap

This command will SSH into your VPS and set up and install everything necessary for Kamal to run your application. It's a good idea to run this separately first in case of any failures; if there are any, they'll be easier to spot and diagnose. It only needs to be run once.

Next, we can start the deploy:

kamal deploy

The deploy command will start the Docker build process locally and then push the image to your registry. Next, Kamal will boot a Traefik container on your server. Kamal will then start the healthcheck process container to ensure it boots and runs without issues. If successful, it'll start a permanent container that Traefik will see and begin directing traffic to it. If everything goes well, your Rails application should be available on port 80 of your VPS. Of course, Rails requires SSL by default for newer applications and will redirect you if you try to access it.

TLS/SSL

In production, you'll want to set up your web application with TLS/SSL to protect your users' privacy. Luckily, the Traefik server has built-in functionality to help us do that! We'll need to make a few modifications to config/deploy.yml. First, tell Kamal that our Traefik server requires TLS/SSL. Add the following to deploy.yml.

traefik:
  options:
    publish:
      - 443:443
    volume:
      - "letsencrypt:/letsencrypt"
  args:
    entrypoints.web.address: ':80'
    entrypoints.websecure.address: ':443'
    certificatesResolvers.letsencrypt.acme.httpchallenge: true
    certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web
    certificatesResolvers.letsencrypt.acme.email: <your email address here>
    certificatesResolvers.letsencrypt.acme.storage: /letsencrypt/acme.json

This config tells Traefik to use LetsEncrypt to acquire an SSL certificate and store it in a mounted volume. A mounted volume is crucial because it allows the certificate to persist if the container or server restarts. Port 443 is the default SSL port. All traffic that arrives via SSL can be tagged as coming from the websecure entry point.

Next, we need to tell Traefik where to send this SSL traffic. Modify the servers part of the deploy.yml:

servers:
  web:
    hosts:
      - <your vps ip address>
    labels:
      traefik.http.routers.maildown-web.rule: 'Host(`<your domain name>`)'
      traefik.http.routers.maildown-web.entrypoints: websecure
      traefik.http.routers.maildown-web.tls.certresolver: letsencrypt

By adding these Docker labels to your application container, Traefik will act as an SSL termination point and direct all websecure traffic to the application. Let's deploy these changes:

First, we reboot Traefik to pick up the new configuration:

kamal traefik reboot

Then, we redeploy our application to pick up the new labels:

kamal deploy

If everything goes well, you can now access your web app via https://.

Where to go from here

I hope that you've found this introduction to Kamal useful. There is a lot more we can do with Kamal. Look for more blog posts about Kamal coming soon. In the meantime, check out some of these links for other Kamal features:

Get the Honeybadger newsletter

Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo
    Roel Bondoc

    Throughout his career, Roel has worked with various languages and frameworks like ColdFusion, C#, VB, Perl, PHP, and Python. He found his true calling working with Ruby on Rails. Now he's a software developer for Honeybadger working on the things he enjoys most!

    More articles by Roel Bondoc
    An advertisement for Honeybadger that reads 'Turn your logs into events.'

    "Splunk-like querying without having to sell my kidneys? nice"

    That’s a direct quote from someone who just saw Honeybadger Insights. It’s a bit like Papertrail or DataDog—but with just the good parts and a reasonable price tag.

    Best of all, Insights logging is available on our free tier as part of a comprehensive monitoring suite including error tracking, uptime monitoring, status pages, and more.

    Start logging for FREE
    Simple 5-minute setup — No credit card required