All Ruby on Rails templates

Rails Deployment (Kamal + Docker)

Deploy Rails with Kamal, Docker, and the Solid Queue/Cable stack.

DevZone Tools820 copiesUpdated Apr 19, 2026Ruby on Rails
# CLAUDE.md — Rails Deployment (Kamal + Docker)

## Why Kamal

- Kamal (formerly MRSK) deploys Dockerized apps to bare-metal or VMs without the Kubernetes complexity.
- Built into Rails 8. Earlier versions: add the `kamal` gem.
- One YAML file (`config/deploy.yml`) describes servers, services, env, and routing.

## Dockerfile

- Two-stage build. The Rails 8 default Dockerfile is the right starting point — don't replace it without a reason.
- Pin Ruby version: `FROM ruby:3.3-slim`.
- Run as a non-root user.
- Precompile assets and bootsnap during build, not at boot.
- `bundle config set --local without 'development test'` so dev gems don't ship.

## kamal config

```yaml
service: myapp
image: myorg/myapp
servers:
  web:
    - 1.2.3.4
  job:
    cmd: bin/jobs
    hosts:
      - 1.2.3.4
registry:
  username: <user>
  password:
    - KAMAL_REGISTRY_PASSWORD
env:
  clear:
    RAILS_ENV: production
  secret:
    - DATABASE_URL
    - SECRET_KEY_BASE
```

- One web role for HTTP, one job role for background workers. Don't run both in one container.
- Use Kamal's secrets feature for sensitive env. They never hit disk on the server.

## Migrations

- `kamal app exec --reuse 'bin/rails db:migrate'` after deploy, before promoting traffic.
- For zero-downtime: backwards-compatible schema changes (add nullable column → deploy → backfill → drop default in next deploy).
- Don't run migrations from the web container at boot — race condition with multi-host deploys.

## Background jobs

- **Solid Queue** in Rails 8 — runs as a separate process, no Redis needed.
- For Sidekiq users: keep the worker container in `servers.workers` and a Redis service.
- `bin/jobs` runs Solid Queue. Set `SOLID_QUEUE_IN_PUMA=false` in the worker container.

## Logging & observability

- Logs go to STDOUT. Kamal forwards them; aggregate in Loki / Datadog / your SaaS of choice.
- `RAILS_LOG_TO_STDOUT=enabled` for the Rails 8 default. JSON formatting via `lograge`.
- Healthchecks: Kamal pings `/up`. Make sure that endpoint doesn't query the DB unless you want DB outages to take down the app.

## Database

- Managed Postgres (RDS, Crunchy Bridge, Render, Neon). DIY only if you have an SRE on the team.
- Connection pooling: `RAILS_MAX_THREADS` × number of pumas × hosts must be ≤ DB max connections. Front with PgBouncer in transaction mode for serverless-style scale.

## Don't

- Don't use Capistrano for new Rails apps — Kamal is the modern path.
- Don't bake secrets into the Docker image. Use Kamal env or pull from a secret manager.
- Don't deploy without a `kamal app version` rollback plan. `kamal rollback` exists; use it.
- Don't run `RAILS_ENV=production bin/rails console` against the live DB without ceremony. It's not a sandbox.

Other Ruby on Rails templates