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:
- Build a new version of a Docker image.
- Start a new container of that image.
- Ensure that the new container is healthy.
- Tell Traefik to start directing traffic to the new container.
- 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.
Install the Kamal gem on your local computer:
gem install kamal
Then, in your Rails application, initialize the setup:
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).
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:
- <your vps ip address>
# If you use another service like DigitalOcean:
# server: registry.digitalocean.com
# - <your-registry-username>
# - KAMAL_REGISTRY_PASSWORD
Fill in the required values as needed. Two environment variables will need our attention:
RAILS_MASTER_KEY. These get populated by the
.env file upon deployment. Edit your
.env file to look something like this:
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
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:
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.
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
certificatesResolvers.letsencrypt.acme.email: <your email address here>
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
- <your vps ip address>
traefik.http.routers.maildown-web.rule: 'Host(`<your domain name>`)'
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:
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: