¿Por qué elegir Kamal en lugar de Kubernetes para desplegar aplicaciones web en un VPS?
Kubernetes resuelve problemas de coordinación a gran escala — descubrimiento de servicios, escalado horizontal automático, espacios de nombres para múltiples equipos — que simplemente no existen en un VPS único o en un cluster pequeño. Su plano de control consume entre 2 y 4 GB de RAM antes de lanzar una sola aplicación. Kamal apunta a un espacio diferente: toma tu Dockerfile, construye la imagen, la envía al registro, la ejecuta en tus servidores vía SSH y cambia el tráfico sin interrupciones gracias a kamal-proxy. Toda la configuración reside en un único archivo config/deploy.yml versionado junto al código. Sin plano de control que mantener, sin certificados de API que renovar, sin YAML distribuido en diez tipos de recursos. Conservas la simplicidad operativa de un VPS — acceso SSH directo, docker ps legible, logs en un archivo — y obtienes un flujo de despliegue profesional con rollback instantáneo, health checks y HTTPS automático.
Lo que te aporta Kamal v2
- Despliegues sin interrupciones — kamal-proxy espera a que los health checks pasen en el nuevo contenedor antes de redirigir el tráfico, y drena las peticiones en vuelo en el antiguo
- Un único comando —
kamal deployencadena build, envío al registro, despliegue SSH y verificación sin pasos manuales - HTTPS automático con Let's Encrypt — kamal-proxy gestiona la renovación de certificados TLS; no se necesita configurar Certbot por separado
- Rollback instantáneo —
kamal rollback [VERSION]redirige el proxy a una imagen ya presente en el servidor en segundos - Gestión estructurada de secretos —
.kamal/secretsadmite lectura desde 1Password, Bitwarden o variables de entorno sin almacenar valores en texto plano en el repositorio - Multi-servidor y multi-rol nativos — servidores web, workers Sidekiq, accesorios Postgres o Redis descritos en un solo archivo, desplegados en paralelo
- Múltiples apps en un solo VPS — desde Kamal 2, varias aplicaciones comparten un kamal-proxy sin conflictos de configuración
- Compatible con cualquier stack — Rails, Django, Node.js, Go, PHP: Kamal solo requiere un Dockerfile y un registro de contenedores
Requisitos previos antes de desplegar con Kamal
En el lado del VPS, Kamal exige Ubuntu 22.04 o 24.04 (o cualquier distribución Linux con Docker 20.10+), acceso SSH por clave (sin contraseña) y al menos 2 vCPU y 2 GB de RAM para una aplicación web estándar con su base de datos. Kamal puede instalar Docker él mismo durante el primer kamal setup, pero la cuenta SSH debe tener derechos sudo. Los puertos 80 y 443 abiertos en entrada y un registro DNS A apuntando a la IP del VPS son indispensables antes de activar el SSL. En tu máquina local, dos opciones: instalar la gema Ruby (gem install kamal, requiere Ruby 3.1+) o usar la imagen Docker oficial. La versión actual es la 2.12.0 (junio de 2026). Prepara también un registro de contenedores — Docker Hub, GitHub Container Registry o un registro privado — junto con sus credenciales.
Kamal v1 vs Kamal v2: qué ha cambiado
Kamal 2, publicado en septiembre de 2024 (incluido por defecto en Rails 8, publicado en noviembre de 2024), reemplaza Traefik por kamal-proxy, un proxy inverso desarrollado internamente por 37signals. El cambio es estructural: Traefik es declarativo (le envías una configuración y converge), mientras que Kamal es imperativo. La versión 1 tenía que consultar la API de Traefik repetidamente para saber si el despliegue había tenido éxito — fuente de condiciones de carrera. Con kamal-proxy, los comandos son directos y sincrónicos. En cuanto a la configuración, el bloque traefik: desaparece de deploy.yml y es reemplazado por proxy: con las claves host, ssl y app_port. Los secretos migran de .env a .kamal/secrets, un archivo shell evaluado que puede llamar a herramientas externas como op read o bw get. El comando kamal upgrade detecta una configuración v1 y propone un plan de migración automatizado. Kamal 2 también introduce el despliegue de varias aplicaciones en un mismo proxy, el modo mantenimiento (kamal app pause) y soporte experimental para despliegues canary.
Instalación y primer despliegue con Kamal v2
Instalar Kamal en tu máquina local
Ejecuta
gem install kamal(requiere Ruby 3.1+) o usa el alias Docker si prefieres evitar Ruby. Verifica la instalación conkamal version— la versión actual es 2.12.0.Inicializar la configuración en tu proyecto
En el directorio raíz del proyecto ejecuta
kamal init. Kamal generaconfig/deploy.ymly.kamal/secrets. Rellena endeploy.yml: nombre del servicio (service: miapp), imagen (image: tuusuario/miapp), lista de servidores y registro.Configurar los secretos y variables de entorno
Añade
.kamal/secretsa tu.gitignore. En ese archivo declara los secretos como variables shell:KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORDo leyéndolos desde 1Password. Enconfig/deploy.ymlreferéncialos bajoenv.secret:para valores cifrados yenv.clear:para variables no sensibles.Configurar el proxy y el SSL
En
config/deploy.ymlañade la sección proxy:proxy: host: app.your-domain.com ssl: true app_port: 3000. kamal-proxy obtendrá automáticamente un certificado Let's Encrypt vía ACME HTTP-01. Asegúrate de que el registro DNS ya apunte a la IP del VPS antes de este paso.Aprovisionar el servidor (solo una vez)
Ejecuta
kamal setup. Kamal se conecta por SSH, instala Docker si está ausente, autentica el registro, inicia kamal-proxy y despliega la primera versión de la aplicación. Este es el único paso de arranque inicial.Desplegar las actualizaciones siguientes
En cada iteración ejecuta
kamal deploy. Kamal construye la imagen, la envía al registro, inicia un nuevo contenedor junto al antiguo, espera que el health check pase, redirige kamal-proxy al nuevo contenedor, drena las conexiones existentes y detiene el antiguo.Verificar el estado y consultar los logs
Tras el despliegue:
kamal app detailsmuestra la versión en ejecución en cada servidor,kamal app logs -fsigue los logs en tiempo real,kamal app exec 'bin/rails console'abre una consola dentro del contenedor en producción.Gestionar los accesorios (base de datos, caché)
Declara Postgres bajo la clave
accessories:endeploy.ymlcon imagen, puerto y volúmenes.kamal accessory boot dbinicia el servicio en el servidor correcto. Los accesorios no pasan por kamal-proxy: se conectan directamente mediante variables de entorno.
Configuración multi-servidor y despliegues paralelos
Kamal despliega hacia todos los servidores de un rol en paralelo por defecto. Para un cluster de servidores web, lista sus IPs bajo servers: web:. Para un despliegue progresivo (rolling), añade boot: limit: 2 wait: 10 — Kamal desplegará en 2 servidores a la vez con 10 segundos entre grupos. Los roles permiten diferenciar los servidores: bajo servers: declara web: (servidores HTTP) y workers: con un comando específico como bundle exec sidekiq. Cada rol puede tener sus propios servidores, secretos y variables. Un único kamal-proxy funciona en el servidor primary (el primero de la lista web); los demás servidores solo ejecutan el contenedor de la aplicación.
Variables de entorno y secretos — buenas prácticas
La separación entre variables claras y secretos es explícita en Kamal 2. En deploy.yml, las variables no sensibles van bajo env: clear: (aparecen en los logs e inspección de contenedor), y los secretos bajo env: secret: — su valor se lee desde .kamal/secrets en el momento del despliegue y se inyecta en el contenedor sin pasar en texto plano por un comando shell visible. Cada rol debe listar explícitamente los secretos que usa. El comando kamal secrets print muestra los valores resueltos para verificar que la lectura desde un gestor de contraseñas funciona correctamente antes de desplegar.
Si un despliegue introduce una regresión, no esperes al próximo ciclo de build: ejecuta kamal rollback [VERSION] para reapuntar kamal-proxy instantáneamente a una imagen ya presente en el VPS. Lista las versiones disponibles con kamal app images. El rollback no reconstruye nada — reapunta el proxy en segundos. Además, kamal app exec 'comando' permite ejecutar migraciones o abrir una consola en el contenedor activo sin abrir manualmente una sesión SSH.
HTTPS automático con kamal-proxy y Let's Encrypt
Kamal-proxy gestiona el ciclo de vida TLS completo: escucha en el puerto 80, responde a los desafíos ACME HTTP-01 de Let's Encrypt, obtiene el certificado, lo almacena en un volumen Docker en el servidor y lo renueva automáticamente antes de su caducidad. El único requisito previo es que el nombre de host declarado en proxy: host: resuelva a la IP del VPS en el momento del primer despliegue — el desafío ACME es síncrono y bloquea el arranque si el DNS no se ha propagado. En servidores con múltiples apps cada una con su propio dominio, kamal-proxy gestiona un certificado separado por dominio vía SNI.
Resolución de errores — problemas frecuentes al desplegar con Kamal
SSH connection timeout: verifica que la IP del servidor sea accesible (ssh -i tu_clave [email protected]) y que el cortafuegos permita el puerto 22. El agente SSH debe estar activo. Target failed to become healthy: el health check por defecto consulta GET /up — si tu aplicación no responde en esa ruta, declara proxy: healthcheck: path: /health en deploy.yml. Verifica también que app_port: coincida con el puerto real del contenedor. Error de autenticación en el registro: ejecuta kamal registry login y reintenta. En CI, verifica que la variable KAMAL_REGISTRY_PASSWORD esté exportada antes de kamal deploy. Conflicto de puertos en el servidor: si un proceso externo ocupa el puerto 80 o 443, kamal-proxy no puede iniciarse; identifícalo con ss -tlnp | grep -E '80|443'. kamal setup falla al instalar Docker: la cuenta SSH debe tener derechos sudo, o instala Docker manualmente y relanza kamal setup.
Integrar Kamal en un pipeline CI/CD con GitHub Actions
Un flujo de trabajo típico de GitHub Actions para Kamal 2 tiene dos trabajos: un trabajo de pruebas (ejecutado en cada push) y un trabajo de despliegue condicional (activado al hacer push a main o al publicar una release). En el trabajo de despliegue: instala Ruby y la gema Kamal, luego ejecuta kamal deploy con los secretos inyectados desde GitHub Secrets. Elementos clave del archivo .github/workflows/deploy.yml: el trabajo de despliegue depende del de pruebas (needs: test), configura las variables de entorno necesarias, instala Kamal con una versión fijada (gem install kamal -v 2.12.0) y ejecuta kamal deploy. El agente SSH se configura vía webfactory/[email protected] con la clave privada almacenada en GitHub Secrets. La variable KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }} inyecta la contraseña del registro de contenedores desde GitHub Secrets.
Kamal v1 vs Kamal v2 — resumen de diferencias
Desplace la tabla
| Kamal v1 | Kamal v2 | |
|---|---|---|
| Proxy | Traefik (declarativo, polling de API) | kamal-proxy (imperativo, comandos directos) |
| Secretos | .env en la raíz del proyecto | .kamal/secrets (shell evaluado, gestores de contraseñas) |
| SSL | Gestionado por Traefik vía ACME | Gestionado por kamal-proxy (Let's Encrypt integrado) |
| Múltiples apps | No soportado de forma nativa | Nativo: varias apps por servidor, un solo proxy |
| Actualización | — | `kamal upgrade` detecta y migra la config v1 |
| Config del proxy en deploy.yml | Bloque `traefik:` | Bloque `proxy:` con `host`, `ssl`, `app_port` |
Kamal en un VPS de ServOrbit — del comando al dominio en órbita
Un VPS Cloud de ServOrbit con Ubuntu 24.04 cumple todos los requisitos de Kamal desde el primer momento: acceso SSH por clave, red de 1 Gbit/s e IP dedicada. El flujo de trabajo habitual: crea un registro DNS A apuntando app.your-domain.com a la IP del VPS, luego ejecuta kamal setup desde tu máquina local — Kamal instala Docker, inicia kamal-proxy, obtiene el certificado Let's Encrypt y despliega tu aplicación en una sola pasada. A partir de entonces, cada kamal deploy desde tu terminal o pipeline CI aplica la actualización sin interrupciones. Para alojar varios proyectos en el mismo VPS, cada uno con su propio dominio y certificado, añade una aplicación en un segundo deploy.yml apuntando al mismo servidor — kamal-proxy enruta por hostname sin reconfiguración. La facturación es la del VPS, sin coste adicional asociado al despliegue.