kamal-deploy
Kamal Deploy Expert
Expert guidance for deploying applications with Kamal - DHH's zero-downtime deployment tool from 37signals.
Step 1: Fetch Latest Documentation (MANDATORY)
BEFORE answering ANY Kamal question, you MUST use the WebFetch tool to get current documentation. The docs below may be outdated - always fetch fresh docs first.
Execute these WebFetch calls in parallel:
-
WebFetch(url: "https://kamal-deploy.org/docs/installation/", prompt: "Extract complete installation and setup guide") -
WebFetch(url: "https://kamal-deploy.org/docs/configuration/overview/", prompt: "Extract all configuration options and deploy.yml structure") -
WebFetch(url: "https://kamal-deploy.org/docs/commands/view-all-commands/", prompt: "Extract all Kamal commands and usage") -
WebFetch(url: "https://kamal-deploy.org/docs/configuration/proxy/", prompt: "Extract proxy, SSL, and health check configuration")
Fetch these additional docs based on user's question:
- Servers/roles:
https://kamal-deploy.org/docs/configuration/servers/ - Accessories (DB, Redis):
https://kamal-deploy.org/docs/configuration/accessories/ - Environment variables:
https://kamal-deploy.org/docs/configuration/environment-variables/ - Docker build options:
https://kamal-deploy.org/docs/configuration/builders/ - Deployment hooks:
https://kamal-deploy.org/docs/hooks/overview/ - Upgrading v1→v2:
https://kamal-deploy.org/docs/upgrading/overview/
Only after fetching fresh docs, use the reference material below as supplementary context.
What is Kamal?
Kamal deploys containerized apps to any server via SSH + Docker. Created by 37signals (DHH's company) to deploy Basecamp, HEY, and other apps.
Core architecture:
- SSHs into servers, installs Docker automatically
- Builds app into Docker container
- Pushes to registry (Docker Hub, GHCR, etc.)
- Pulls and runs on target servers
- kamal-proxy handles routing, SSL (Let's Encrypt), zero-downtime
Mental model: Hetzner/DigitalOcean = the computer, Kamal = deploys your app to it
Before You Start
Check these first to avoid common friction:
-
Kamal version - Run
kamal version. If on 1.x, upgrade withgem install kamal. Config syntax changed significantly (1.x usestraefik, 2.x usesproxy). -
Local Docker situation - Ask the user if they have Docker working locally. If not (or if Docker Desktop is problematic on macOS), configure a remote builder:
builder: arch: amd64 remote: ssh://root@SERVER_IPThis builds on the target server and avoids local Docker entirely.
-
37signals open-source repos - If deploying Campfire, HEY, or other 37signals apps, immediately delete
.env.erb- it uses their internal 1Password setup and will fail withop: command not found. -
Registry access - Confirm the user has a container registry (Docker Hub, GHCR) and knows their credentials before writing config.
Quick Start
# Install (or upgrade)
gem install kamal
# Initialize in project
kamal init
# First deploy (installs Docker, proxy, deploys app)
kamal setup
# Subsequent deploys
kamal deploy
Essential Commands
| Command | Purpose |
|---|---|
kamal setup |
First deploy - installs Docker, proxy, deploys |
kamal deploy |
Deploy new version |
kamal rollback |
Revert to previous version |
kamal app logs |
View application logs |
kamal app exec -i bash |
SSH into running container |
kamal accessory boot <name> |
Start accessory (db, redis) |
kamal proxy reboot |
Restart kamal-proxy |
kamal remove |
Remove everything from servers |
Minimal config/deploy.yml
service: my-app
image: username/my-app
servers:
- 123.45.67.89
registry:
username: username
password:
- KAMAL_REGISTRY_PASSWORD
proxy:
ssl: true
host: myapp.com
env:
secret:
- RAILS_MASTER_KEY
- DATABASE_URL
Secrets Management
Secrets live in .kamal/secrets:
# .kamal/secrets
KAMAL_REGISTRY_PASSWORD=ghp_xxxxxxxxxxxx
RAILS_MASTER_KEY=abc123def456
DATABASE_URL=postgres://user:pass@db:5432/app
Reference in deploy.yml:
env:
clear:
RAILS_ENV: production
secret:
- RAILS_MASTER_KEY
- DATABASE_URL
Multi-Server with Roles
servers:
web:
hosts:
- 123.45.67.89
- 123.45.67.90
workers:
hosts:
- 123.45.67.91
cmd: bin/jobs
proxy: false # Workers don't need proxy
Accessories (Databases, Redis)
accessories:
db:
image: postgres:16
host: 123.45.67.89
port: 5432
env:
clear:
POSTGRES_DB: app_production
secret:
- POSTGRES_PASSWORD
directories:
- data:/var/lib/postgresql/data
redis:
image: redis:7
host: 123.45.67.89
port: 6379
directories:
- data:/data
SSL Configuration
Automatic (Let's Encrypt):
proxy:
ssl: true
host: myapp.com # Must point to server IP
Custom certificate:
proxy:
ssl:
certificate_pem:
- SSL_CERTIFICATE
private_key_pem:
- SSL_PRIVATE_KEY
Health Checks
proxy:
healthcheck:
interval: 3
path: /up
timeout: 3
App must return 200 on /up (Rails default) or configured path.
Destinations (Staging/Production)
Create config/deploy.staging.yml:
servers:
- staging.myapp.com
proxy:
host: staging.myapp.com
Deploy: kamal deploy -d staging
Secrets: .kamal/secrets.staging
Hooks
Place in .kamal/hooks/ (no file extension):
Available hooks:
pre-connect,pre-build,pre-deploy,post-deploypre-app-boot,post-app-bootpre-proxy-reboot,post-proxy-reboot
Example .kamal/hooks/post-deploy:
#!/bin/bash
curl -X POST "https://api.honeybadger.io/v1/deploys" \
-d "deploy[revision]=$KAMAL_VERSION"
Dockerfile Requirements
Kamal needs a Dockerfile. For Rails:
FROM ruby:3.3-slim
WORKDIR /app
# Install dependencies
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
COPY Gemfile* ./
RUN bundle install
COPY . .
RUN bundle exec rails assets:precompile
EXPOSE 80
CMD ["bin/rails", "server", "-b", "0.0.0.0", "-p", "80"]
Note: Kamal 2.x defaults to port 80 (not 3000).
Common Issues
"Container not healthy"
- Check
/upendpoint returns 200 - Increase
deploy_timeoutif app boots slowly - Check logs:
kamal app logs
"Permission denied"
- Ensure SSH key is added:
ssh-add ~/.ssh/id_rsa - Check SSH user has Docker access
Registry auth failed
- Verify
KAMAL_REGISTRY_PASSWORDin.kamal/secrets - For GHCR: use personal access token with
write:packages
"Address already in use"
- Another service on port 80/443
- Run
kamal proxy rebootor checkdocker pson server
Kamal vs Alternatives
| Kamal | Kubernetes | Heroku | |
|---|---|---|---|
| Complexity | Low | High | None |
| Cost | VPS only | VPS + overhead | $$$ |
| Control | Full | Full | Limited |
| Zero-downtime | Yes | Yes | Yes |
| SSL | Auto | Manual | Auto |
| Learning curve | Hours | Weeks | Minutes |
Best Practices
- Always test locally first:
docker build . && docker run -p 3000:80 <image> - Use staging destination before production
- Keep secrets out of git:
.kamal/secretsin.gitignore - Set up monitoring: Use hooks to notify on deploy
- Regular backups: Especially accessory volumes
- Use asset bridging for Rails:
asset_path: /app/public/assets
Reference Files
For detailed configuration options, see:
- references/configuration.md - Complete deploy.yml reference
- references/troubleshooting.md - Common issues and solutions
More from nityeshaga/claude-code-essentials
coding-tutor
Personalized coding tutorials that build on your existing knowledge and use your actual codebase for examples. Creates a persistent learning trail that compounds over time using the power of AI, spaced repetition and quizzes. Uses cloud storage via MCP for tutorials and learner profiles.
30prompt-engineer
Expert prompt engineering for AI systems. Use when the user wants to write or review prompts for AI, create instructions for AI systems, build system prompts, review or improve existing prompts, optimize AI instructions, or create any form of written communication intended for AI consumption (Claude, GPT, or other LLMs).
10skill-creator
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, update or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
8dhh-rails-expert
Expert at writing and reviewing Rails code following DHH's style as practiced at 37signals. Use when writing new Rails code, reviewing Rails code, making architectural decisions in Rails apps.
7ai-tool-designer
Guide for designing effective tools for AI agents. Use when creating tools for custom agent systems or any AI tool interfaces. Provides principles for tool naming, input/output design, error handling, and evaluation methodologies that maximize agent effectiveness.
6mcp-builder
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
6