itsez.dev
๐Ÿ“–Tutorial

Deploy a web app with Kamal

2026-07-30ยท4 min readยทCI/CD & code

Kamal is a Ruby gem that runs on your deployment machine (laptop or CI runner), not on the server. It orchestrates Docker containers on a VPS over SSH. This guide walks through installing Kamal, configuring a deploy, and running your first deployment.

Prerequisites

  • A deployment machine (your laptop or CI runner) with Ruby installed (2.7+). This is where Kamal runs.
  • A target VPS with SSH access (root or a user with sudo). No software needs to be pre-installed.
  • A Docker registry account (Docker Hub, GHCR, or any private registry) with credentials.
  • Your web app with a Dockerfile in the repository root that builds a runnable image.
  • A domain name with an A/AAAA record pointing to your VPS IP.

Kamal is a client-side tool. It never runs on the server. The VPS is a blank machine that only needs SSH reachability and ports 80 and 443 open in the firewall.

Step 1: Install Kamal on your deployment machine

Install the Kamal Ruby gem:

gem install kamal

Verify it is available:

kamal version

That is all. Do not install Kamal on the VPS. The VPS will receive commands over SSH from this machine.

Step 2: Initialize Kamal in your application

Navigate to your application root and run:

cd /path/to/your-app
kamal init

This creates two things:

  • config/deploy.yml โ€” the deployment configuration file
  • .kamal/secrets โ€” a local file for sensitive values (do not commit this file)

Both files are meant to be edited by you in the next steps.

Step 3: Configure deploy.yml

Open config/deploy.yml and replace the template with values for your project. A minimal working configuration:

service: myapp
image: your-registry-user/myapp

servers:
  web:
    - your-domain.com

proxy:
  ssl: true
  host: your-domain.com
  app_port: 3000

registry:
  server: ghcr.io
  username: your-registry-user
  password: KAMAL_REGISTRY_PASSWORD

env:
  clear:
    RAILS_ENV: production
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL

Key fields:

  • service โ€” a name for your app (used for container naming)
  • image โ€” the full registry image name
  • servers.web โ€” list of your VPS hostnames or IPs
  • proxy โ€” kamal-proxy will terminate SSL with Let's Encrypt and forward traffic to app_port
  • registry โ€” credentials for pushing and pulling images
  • env โ€” environment variables passed to the container

For accessories like PostgreSQL or Redis, you can add an accessories section, but start without them for the first deploy.

Step 4: Set secrets

Edit .kamal/secrets to define the values referenced in deploy.yml:

KAMAL_REGISTRY_PASSWORD=your-personal-access-token
RAILS_MASTER_KEY=your-rails-master-key
DATABASE_URL=postgres://user:pass@host/db

The .kamal/secrets file is local only. On CI, inject these values through the CI secret store and pass them via environment variables that Kamal reads.

Never commit .kamal/secrets to version control. The .kamal directory is in .gitignore by default.

Step 5: Set up the VPS with kamal setup

This is the key command. It does everything in one shot:

kamal setup

Kamal will SSH into your VPS and:

  1. Install Docker if it is not already present
  2. Start the kamal-proxy container, which binds ports 80 and 443
  3. Obtain a Let's Encrypt SSL certificate for your domain automatically
  4. Pull your application image from the registry
  5. Start your application container behind the proxy

No manual Docker installation, no Nginx configuration, no certbot. The VPS goes from blank to running your app in one command.

Step 6: Deploy updates

After the initial setup, deploy new versions with:

kamal deploy

This builds or pulls the new image, stops the old container gracefully, starts the new one, and verifies the health check. Kamal rolls back automatically if the health check fails.

Maintenance

  • Upgrade Kamal: gem update kamal on your deployment machine
  • Check logs: kamal app logs
  • Run a command inside a container: kamal app exec 'rails console'
  • Restart the app: kamal app restart
  • Rollback: kamal deploy --version=<previous-version>
  • Upgrade kamal-proxy on the server: kamal proxy upgrade

Kamal does not manage databases. Back up persistent data separately and document how to recreate your server from the repository and secret store alone.

Tools mentioned

Kamal

โ†—

Deploy web applications to any VPS with zero infrastructure complexity using Docker.

FreeNo cardOSS

Free and open source. No platform fees. Deploy to any server you control with only Docker as a dependency.

ABOUT US

Honest, independent, no fluff.

No paid placements. Just a clear look at what this does, what it costs, and what to know before you commit.

Read moreโ†’

FAQ

Questions, answered.

Does Kamal run on the server?๏ผ‹

No. Kamal runs from your workstation or CI and connects to the VPS over SSH. The server only needs SSH access and open ports 80 and 443.

Does the VPS need Docker pre-installed?๏ผ‹

No. Kamal's `setup` command installs Docker and kamal-proxy automatically. You only need a clean VPS with SSH access.

Do I need a reverse proxy like Nginx or Caddy?๏ผ‹

No. Kamal deploys its own kamal-proxy container that handles ports 80 and 443 with automatic Let's Encrypt SSL certificates.