kamal-deployment

star 1

Deploy containerized applications (especially Rails) to VPS using Kamal 2. Covers deploy.yml configuration, accessories (PostgreSQL, Redis, Sidekiq), SSL/TLS, secrets management, CI/CD with GitHub Actions, database backups, server hardening, debugging, and scaling. Use when setting up Kamal, configuring deployments, troubleshooting deploy issues, or managing production infrastructure with Kamal.

ofrades By ofrades schedule Updated 6/10/2026

name: kamal-deployment description: Deploy containerized applications (especially Rails) to VPS using Kamal 2. Covers deploy.yml configuration, accessories (PostgreSQL, Redis, Sidekiq), SSL/TLS, secrets management, CI/CD with GitHub Actions, database backups, server hardening, debugging, and scaling. Use when setting up Kamal, configuring deployments, troubleshooting deploy issues, or managing production infrastructure with Kamal.

Kamal 2 Deployment

Kamal is a deployment tool by 37signals that deploys containerized applications to any Linux server using Docker, SSH, and Kamal Proxy. It offers zero-downtime deploys, rolling restarts, automatic SSL/TLS certificates, and auxiliary services management.

Quick Start

# Install
gem install kamal

# Initialize in your project
kamal init
# Creates: config/deploy.yml, .kamal/secrets, .kamal/hooks/

# First deploy (bootstraps servers + deploys)
kamal setup

# Subsequent deploys
kamal deploy

Key Concepts

  • Service: Your application name, used to uniquely configure containers
  • Server: A virtual or physical host running your application image
  • Role: A server group running the same command (e.g., web, job)
  • Accessory: A long-running auxiliary service (database, Redis) with independent lifecycle
  • Kamal Proxy: Reverse proxy for zero-downtime deploys and SSL termination on each server
  • Kamal 2 provides its own private network called kamal - do NOT add a custom private network in your config

Configuration Reference

For complete deploy.yml configuration, see configuration.md.

Workflows

Initial Setup

  1. Run kamal init to generate config files
  2. Configure config/deploy.yml (see configuration.md)
  3. Set up .kamal/secrets with registry credentials and app secrets
  4. Ensure your app has a Dockerfile exposing port 80 with a /up health check
  5. Set config.assume_ssl = true and config.force_ssl = true in production.rb
  6. Exclude /up from host authorization in Rails 7+:
    config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
    
  7. Run kamal setup for the first deployment

Deploying Updates

kamal deploy                    # Full deploy (build + push + deploy)
kamal deploy --skip-push        # Deploy existing image from registry
kamal deploy --version=VERSION  # Deploy specific version

Managing Accessories

kamal accessory boot all        # Boot all accessories
kamal accessory boot postgres   # Boot specific accessory
kamal accessory reboot redis    # Reboot an accessory
kamal accessory remove postgres # Remove an accessory
kamal accessory details postgres
kamal accessory logs postgres

Maintenance & Debugging

# Logs
kamal app logs                  # Application logs
kamal app logs -f               # Follow logs
kamal app logs -r web           # Logs for specific role
kamal proxy logs                # Proxy logs

# Console access
kamal app exec -i 'bin/rails console'
kamal app exec -i --reuse bash  # Shell into running container
kamal app exec --primary "bin/rails about"

# Rollback
kamal app containers            # List available versions
kamal rollback [VERSION]         # Rollback to version

# Redeploy (skip bootstrap, proxy setup, pruning, registry login)
kamal redeploy

# Locks
kamal lock status               # Check deploy lock
kamal lock acquire -m "reason"  # Prevent deploys
kamal lock release              # Allow deploys again

# Server management
kamal server bootstrap          # Bootstrap servers with Docker
kamal details                   # Show details about all containers
kamal audit                     # Show audit log from servers
kamal prune                     # Prune old images and containers
kamal config                    # Show combined config (includes secrets!)
kamal docs [SECTION]            # Show Kamal configuration docs

# Cleanup
kamal remove                    # Remove everything from servers

Global Flags

Flag Description
-v, --verbose Detailed logging
-q, --quiet Minimal logging
--version=VERSION Run against specific app version
-p, --primary Primary host only
-h, --hosts=HOSTS Comma-separated hosts (supports wildcards)
-r, --roles=ROLES Comma-separated roles (supports wildcards)
-d, --destination Deployment destination
-H, --skip-hooks Skip hook execution

Database Operations

# Run migrations via entrypoint (recommended)
# bin/docker-entrypoint handles db:prepare automatically

# Or via pre-deploy hook
kamal app exec -p -q -d $KAMAL_DESTINATION --version $KAMAL_VERSION "rails db:migrate"

# Database backup (with S3 backup accessory)
kamal accessory exec s3_backup "sh backup.sh"
kamal accessory exec s3_backup "sh restore.sh"

Architecture Patterns

For complete examples of single-server and multi-server setups, see examples.md.

Single Server (Rails + PostgreSQL + Redis + Sidekiq)

All services on one VPS with Let's Encrypt SSL. Best for small-to-medium apps.

Multi-Server (Scaled)

Separate servers for web, job, database, and cache behind a load balancer on a private network. Best for high-traffic apps.

Hooks

Custom scripts in .kamal/hooks/ that run at deployment points. If a hook returns non-zero, the command aborts.

Available: docker-setup, pre-connect, pre-build, pre-deploy, post-deploy, pre-app-boot, post-app-boot, pre-proxy-reboot, post-proxy-reboot.

For details, see configuration.md.

Upgrading from Kamal 1

kamal upgrade              # In-place upgrade from Kamal 1 to 2
kamal upgrade --rolling    # Zero-downtime upgrade
kamal downgrade            # Reverse if needed

Common Gotchas

  • Kamal 2 creates its own kamal network - remove any custom private network from your config
  • Always set config.assume_ssl = true in production.rb when using SSL
  • Do NOT use your domain name as the VM hostname - it overrides /etc/resolv.conf
  • Docker port exposure bypasses UFW - closing ports in UFW is not enough, Docker rules are higher in iptables
  • Short deploy_timeout causes failures on underpowered servers - increase it if deploys fail
  • Asset bridging must be explicitly configured with asset_path - it's not automatic
  • Accessories must be removed before moving to a new destination
  • Kamal 2 doesn't support ERB in config/deploy.yml (unlike Kamal 1)
  • Set config.reload_routes = false in Devise initializer to fix ActionController::RoutingError
  • Enable forward_headers: true in proxy config when behind Cloudflare to preserve real client IPs

CI/CD

For GitHub Actions deployment workflows, see cicd.md.

Backups

For database backup strategies with S3, see backups.md.

Server Hardening

For production server security setup, see server-hardening.md.

Logging & Monitoring

For Vector log aggregation and structured logging, see logging.md.

Install via CLI
npx skills add https://github.com/ofrades/bursa --skill kamal-deployment
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator