- name
- kamal-deploy
- description
- Deploy and operate Rails applications with Kamal 2; troubleshoot deployment infrastructure.
# Kamal Deploy
Servers need Docker, SSH access, and ports 22/80/443 open. Provision with Ansible or cloud-init.
## Configuration: config/deploy.yml
### Minimal Setup
```yaml
service: myapp
image: myapp
servers:
web:
- 203.0.113.10
proxy:
ssl: true
host: myapp.com
registry:
username: username
password:
- KAMAL_REGISTRY_PASSWORD
env:
clear:
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: "true"
secret:
- RAILS_MASTER_KEY
```
### Multi-Role Setup (Web + Job Worker)
```yaml
service: myapp
image: myapp
servers:
web:
- 203.0.113.10
job:
hosts:
- 203.0.113.10
cmd: bin/jobs start
proxy:
ssl: true
host: myapp.com
registry:
username: username
password:
- KAMAL_REGISTRY_PASSWORD
env:
clear:
RAILS_ENV: production
SOLID_QUEUE_IN_PUMA: false
secret:
- RAILS_MASTER_KEY
```
**Job worker notes:**
- `cmd: bin/jobs start` runs Solid Queue in a separate container
- Set `SOLID_QUEUE_IN_PUMA: false` to disable in-process queue
- Job role has no proxy, only web role serves HTTP traffic
- Fiber workers (`fibers:` in `config/queue.yml`) make the separate container the safer default: in-Puma mode forces `isolation_level = :fiber` on the web process too
### With Local Registry
Eliminates Docker Hub dependency, rate limits, and external costs:
```yaml
registry:
server: localhost:5555
username: ignored
password:
- KAMAL_REGISTRY_PASSWORD
```
Deploy the registry as an accessory:
```yaml
accessories:
registry:
image: registry:2
host: 203.0.113.10
port: "5555:5000"
volumes:
- registry_data:/var/lib/registry
```
### With Accessories
```yaml
accessories:
db:
image: postgres:16
host: 203.0.113.10
port: 5432
env:
clear:
POSTGRES_DB: myapp_production
secret:
- POSTGRES_PASSWORD
directories:
- data:/var/lib/postgresql/data
options:
shm-size: 256m
redis:
image: redis:7-alpine
host: 203.0.113.10
port: 6379
directories:
- data:/data
cmd: redis-server --appendonly yes
```
### Docker Volumes for Persistence
For SQLite + ActiveStorage apps, mount a named volume:
```yaml
servers:
web:
hosts:
- 203.0.113.10
volumes:
- myapp_storage:/rails/storage
labels:
docker-volume-backup.stop-during-backup: "true"
job:
hosts:
- 203.0.113.10
cmd: bin/jobs start
volumes:
- myapp_storage:/rails/storage
```
Both web and job containers share the same volume for database access.
## Proxy Configuration (kamal-proxy)
Kamal 2 uses kamal-proxy (not Traefik). It handles SSL termination, routing, and zero-downtime deploys.
### Basic SSL
```yaml
proxy:
ssl: true
host: myapp.com
```
Automatic Let's Encrypt certificate provisioning, no manual cert management.
### Custom Port
```yaml
proxy:
ssl: true
host: myapp.com
app_port: 3000
```
### Multiple Hosts
```yaml
proxy:
ssl: true
hosts:
- myapp.com
- www.myapp.com
```
### Health Check
```yaml
proxy:
ssl: true
host: myapp.com
healthcheck:
path: /up
interval: 3
timeout: 3
```
### Response Timeout
```yaml
proxy:
ssl: true
host: myapp.com
response_timeout: 30
```
## Detailed Reference
Load [detailed-reference.md](references/detailed-reference.md) for extended examples, templates, and advanced patterns.
Ver en GitHub