Tutorial

Despliegue

Desplegar aplicaciones web con Kamal en un VPS

Kamal (antes conocido como MRSK), desarrollado por 37signals, despliega aplicaciones en contenedores en uno o varios servidores VPS desde tu máquina local, sin necesidad de un orquestador pesado. Desde la versión 2, publicada en septiembre de 2024 (incluida por defecto en Rails 8, publicado en noviembre de 2024), reemplaza Traefik por su propio proxy dedicado (kamal-proxy) y centraliza la gestión de secretos en `.kamal/secrets`. El comando `kamal deploy` coordina la construcción de la imagen Docker, el envío al registro y el cambio de tráfico sin interrupciones en una sola pasada.

12 min de lectura8 pasos
Contenido· ¿Por qué elegir Kamal en lugar de Kubernetes para desplegar aplicaciones web en un VPS?1/12
  1. 01¿Por qué elegir Kamal en lugar de Kubernetes para desplegar aplicaciones web en un VPS?
  2. 02Lo que te aporta Kamal v2
  3. 03Requisitos previos antes de desplegar con Kamal
  4. 04Kamal v1 vs Kamal v2: qué ha cambiado
  5. 05Instalación y primer despliegue con Kamal v2
  6. 06Configuración multi-servidor y despliegues paralelos
  7. 07Variables de entorno y secretos — buenas prácticas
  8. 08HTTPS automático con kamal-proxy y Let's Encrypt
  9. 09Resolución de errores — problemas frecuentes al desplegar con Kamal
  10. 10Integrar Kamal en un pipeline CI/CD con GitHub Actions
  11. 11Kamal v1 vs Kamal v2 — resumen de diferencias
  12. 12Kamal en un VPS de ServOrbit — del comando al dominio en órbita

¿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. Solo para instalarlo con kubeadm, la documentación oficial pide 2 GB de RAM por máquina y 2 CPU para el plano de control, antes de cualquier 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 deploy encadena 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/secrets admite 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 necesita un servidor Linux accesible por SSH con clave (sin contraseña); su documentación no impone distribución ni tamaño, pero cuenta con 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 (script get.docker.com), pero para ello necesita acceso root por SSH — Kamal se conecta como root por defecto. 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, con un entorno Ruby) 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. La configuración se convierte a mano; kamal upgrade migra después los servidores: retira Traefik, inicia kamal-proxy y reinicia la aplicación y los accesorios en la nueva red. Kamal 2 también introduce el despliegue de varias aplicaciones en un mismo proxy y el modo mantenimiento (kamal app maintenance, y luego kamal app live para volver a estar en línea).

Instalación y primer despliegue con Kamal v2

  1. Instalar Kamal en tu máquina local

    Ejecuta gem install kamal (requiere un entorno Ruby) o usa el alias Docker si prefieres evitar Ruby. Verifica la instalación con kamal version — la versión actual es 2.12.0.

  2. Inicializar la configuración en tu proyecto

    En el directorio raíz del proyecto ejecuta kamal init. Kamal genera config/deploy.yml y .kamal/secrets. Rellena en deploy.yml: nombre del servicio (service: miapp), imagen (image: tuusuario/miapp), lista de servidores y registro.

  3. Configurar los secretos y variables de entorno

    Añade .kamal/secrets a tu .gitignore. En ese archivo declara los secretos como variables shell: KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD o leyéndolos desde 1Password. En config/deploy.yml referéncialos bajo env.secret: para valores secretos y env.clear: para variables no sensibles.

  4. Configurar el proxy y el SSL

    En config/deploy.yml añ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 (puertos 80 y 443 abiertos). Asegúrate de que el registro DNS ya apunte a la IP del VPS antes de este paso.

  5. 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.

  6. 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.

  7. Verificar el estado y consultar los logs

    Tras el despliegue: kamal app details muestra la versión en ejecución en cada servidor, kamal app logs -f sigue los logs en tiempo real, kamal app exec -i 'bin/rails console' abre una consola dentro del contenedor en producción.

  8. Gestionar los accesorios (base de datos, caché)

    Declara Postgres bajo la clave accessories: en deploy.yml con imagen, puerto (ligado al host local, port: "127.0.0.1:5432:5432", nunca publicado en todas las interfaces) y volúmenes. kamal accessory boot db inicia 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. kamal-proxy funciona en cada servidor del rol principal (web por defecto); los demás roles, como workers, no lo ejecutan. Con varios servidores web, coloca un balanceador de carga delante: el HTTPS automático de kamal-proxy supone un despliegue en un solo servidor.

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 escribe en un archivo de entorno en el servidor, en lugar de pasarse en texto plano en el comando docker run. Un secreto de .kamal/secrets solo se inyecta si figura bajo env: secret:, en la raíz para todos los roles o en el rol o accesorio que lo 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' ejecuta migraciones en un contenedor de la versión en curso (--reuse para el contenedor activo, -i para una consola) 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 los puertos 80 y 443, responde a los desafíos ACME de Let's Encrypt, obtiene el certificado, lo almacena 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 y que los puertos 80 y 443 estén abiertos — el certificado se solicita en la primera conexión HTTPS, y el desafío ACME falla mientras el DNS no se haya propagado. En un servidor con varias apps, cada una con su propio dominio, kamal-proxy enruta por nombre de host y gestiona un certificado separado por dominio. Este HTTPS automático supone un despliegue en un solo servidor: más allá, termina el TLS en un balanceador de carga.

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 instalación automática requiere acceso root por SSH; si no, 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 v1Kamal v2
ProxyTraefik (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)
SSLGestionado por Traefik vía ACMEGestionado por kamal-proxy (Let's Encrypt integrado)
Múltiples appsNo soportado de forma nativaNativo: varias apps por servidor, un solo proxy
Actualización—`kamal upgrade` migra los servidores (config a convertir a mano)
Config del proxy en deploy.ymlBloque `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.

Controle sus despliegues Kamal en un VPS Cloud ServOrbit

Aprovisione un VPS Cloud con la plantilla Despliegue y acceso SSH por clave: Kamal instala Docker en él y despliega su aplicación en zero-downtime desde el primer comando.