Kamal no se ejecuta en tu VPS. Es una herramienta de despliegue que instalas en tu propia máquina o en tu runner de CI, y que se conecta al servidor por SSH para hacer su trabajo. Basecamp la creó para publicar aplicaciones Rails sin Kubernetes, pero despliega cualquier cosa que se construya como imagen Docker.
Esa distinción cambia lo que estás buscando. El VPS es el destino de Kamal, así que tiene que ser lo bastante grande para tu aplicación, sus bases de datos y unos días de versiones de imagen. La huella de Kamal en el servidor es cero.
Qué deja Kamal realmente en el servidor
kamal setup se conecta por SSH (como root por defecto, autenticado con tu clave SSH) y ejecuta tres pasos: instalar Docker si no está, arrancar los accesorios que hayas declarado y desplegar la aplicación. Después, el host ejecuta:
- kamal-proxy: un proxy HTTP pequeño que ocupa los puertos 80 y 443, obtiene certificados de Let’s Encrypt y retiene las peticiones entrantes durante un despliegue hasta que el contenedor de reemplazo está listo.
- Tus contenedores de aplicación: un conjunto por cada rol definido en
config/deploy.yml. - Los accesorios: Postgres, Redis o los servicios que hayas listado en la configuración.
Kamal en sí es una gema (gem install kamal, versión 2.12.0 en el momento de escribir esto) y no deja ningún demonio detrás.
Requisitos previos
Antes de empezar, ten a mano:
- Un VPS con una instalación limpia de Linux y acceso SSH como root mediante clave (Ubuntu 24.04 es una opción sensata)
- Un registro de contenedores del que tu servidor pueda descargar: Docker Hub, GitHub Container Registry o el de tu proveedor
- Ruby en local para
gem install kamal; sin Ruby también puedes ejecutar Kamal desde una imagen de contenedor, con algunas limitaciones - Un
Dockerfilefuncional para tu aplicación
Elegir proveedor de VPS
Como el servidor solo ejecuta contenedores, juzga a los proveedores por la fiabilidad de red, el margen de disco y la rapidez con la que puedes reconstruir un host:
| Proveedor | Precio | Características | Enlace de afiliado |
|---|---|---|---|
| Contabo VPS | 5.99 EUR/mes | 400 GB de disco absorben imágenes grandes e historial largo de rollback | Contabo VPS |
| Hetzner Cloud | 5.49 EUR/mes | 2 vCPU / 4 GB / 40 GB NVMe, snapshots para rehacer el host rápido | Hetzner Cloud |
| DigitalOcean | 6 USD/mes | La mejor documentación y API para automatizar el host | DigitalOcean |
| Vultr | 5 USD/mes | Amplia elección de regiones para acercar la app a sus usuarios | Vultr |
| Linode | 5 USD/mes | Precios predecibles, configuración de red sencilla | Linode |
Para una comparativa completa, consulta nuestra comparativa de VPS.
DigitalOcean es el punto de partida más sencillo, porque su documentación cubre justo el trabajo a nivel de host que Kamal no hace por ti: reglas de firewall, swap y actualizaciones automáticas.
Preparar el servidor
- Crea el VPS con una imagen mínima de Ubuntu 24.04 y tu clave SSH asociada.
- Comprueba que el acceso SSH como root funciona, porque así se conecta Kamal por defecto:
ssh root@tu-ip-vps
- Abre solo lo necesario. kamal-proxy termina TLS en el servidor, así que bastan los puertos 22, 80 y 443:
ufw allow 22,80,443/tcp && ufw enable
No hace falta que instales Docker: Kamal lo hace en el primer kamal setup si no está presente.
Instalar Kamal y escribir la configuración
En tu propia máquina, dentro del directorio de tu aplicación:
gem install kamal
kamal init
kamal init crea config/deploy.yml. Una configuración mínima funcional necesita un nombre de servicio, una imagen y al menos un host:
service: myapp
image: your-registry-user/myapp
servers:
web:
hosts:
- 203.0.113.10
registry:
username: your-registry-user
password:
- KAMAL_REGISTRY_PASSWORD
proxy:
ssl: true
host: app.example.com
Los secretos viven en .kamal/secrets, que Kamal lee en el momento del despliegue. Primero busca .kamal/secrets-common y después .kamal/secrets:
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
Mantén ese fichero fuera del control de versiones y saca el valor de tu entorno de shell o de un gestor de contraseñas.
El primer despliegue
kamal setup
Ese único comando instala Docker, arranca los accesorios, construye y sube tu imagen y levanta la aplicación. Todos los despliegues posteriores se reducen a:
kamal deploy
Para ver qué se está ejecutando en el host:
kamal app containers
Dónde se construye la imagen
Por defecto Kamal construye en local, en la máquina desde la que lo lanzas, y luego sube al registro. El servidor solo descarga. Si tu portátil es arm64 y el VPS es amd64, fija la arquitectura de destino o apunta Kamal a un builder remoto:
builder:
arch: amd64
remote: ssh://[email protected]
La compilación cruzada por emulación es lo bastante lenta como para notarse en cada despliegue. Si el VPS es tu única máquina amd64, puede hacer también de builder, pero entonces dimensiónalo para una construcción de Docker y no solo para ejecutar la aplicación, lo que normalmente implica subir un plan.
Dimensionar el disco
Kamal conserva contenedores e imágenes antiguos en el servidor para que kamal rollback pueda arrancar una versión previa sin volver al registro. Por defecto los limpia a los tres días. Calcula los datos propios de tu aplicación más unos tres días de versiones de imagen y sus capas base compartidas.
Una imagen de 1 GB desplegada un par de veces al día vive cómodamente en los 40 GB NVMe de Hetzner. Una imagen de 3 GB llena un disco de 25 GB en una semana, y un disco lleno rompe el siguiente despliegue, no el actual, lo que hace fácil pasarlo por alto hasta que se vuelve urgente.
El cambio sin cortes
kamal-proxy solo lleva el tráfico al contenedor nuevo cuando este responde 200 a GET /up. De ahí se siguen dos cosas:
- Tu aplicación necesita un endpoint
/up. Rails trae uno; otros frameworks suelen requerir unas pocas líneas. - Ese endpoint debe devolver 200 únicamente cuando la aplicación ya puede atender peticiones. Si responde antes de que las conexiones a la base de datos estén listas, los usuarios llegan demasiado pronto al contenedor nuevo.
Si la comprobación de salud nunca pasa, el despliegue expira y Kamal deja al contenedor antiguo sirviendo el tráfico.
Asegurar el despliegue
- Kamal se conecta como root por SSH, así que desactiva por completo la autenticación por contraseña y apóyate en claves.
- Deja que kamal-proxy gestione TLS. Poner un segundo proxy inverso delante solo complica el camino de los certificados.
- Añade swap en los hosts de 4 GB. Durante un despliegue conviven brevemente el contenedor antiguo y el nuevo, y un host que empieza a hacer swap en ese momento se vuelve lo bastante lento como para agotar el tiempo de la comprobación de salud.
- Guarda la contraseña del registro en
.kamal/secretsy no enconfig/deploy.yml, que sí se versiona.
Consejos finales
- Ejecuta
kamal deploydesde CI en cuanto el camino manual funcione. La configuración es idéntica; solo cambia el origen de los secretos. kamal rollback [versión]es instantáneo mientras la imagen antigua siga en disco, así que comprueba conkamal app containersque aún existe un destino de rollback.- Desplegar una segunda aplicación en el mismo host está soportado en Kamal 2: kamal-proxy enruta por nombre de host, así que a cada aplicación le basta con su propio
servicey suproxy.host.
Para profundizar en la elección del servidor, consulta nuestra comparativa de VPS.
Frequently asked questions
¿Kamal se ejecuta en el VPS o en mi propia máquina?
Kamal se ejecuta en tu máquina o en tu runner de CI. Es una gema de Ruby que se conecta al servidor por SSH, instala Docker si falta y arranca tus contenedores. En el VPS solo queda kamal-proxy junto a tus contenedores de aplicación y accesorios, nunca Kamal en sí.
¿Cuánto disco necesita un VPS usado como destino de Kamal?
Calcula los datos de tu aplicación más unos tres días de versiones de imagen, porque Kamal conserva contenedores e imágenes antiguos para los rollbacks y solo los limpia a los tres días. Una imagen de 1 GB desplegada varias veces al día cabe en 40 GB; una de 3 GB en un disco de 25 GB, no.
¿Por qué mi despliegue de Kamal expira y vuelve atrás?
kamal-proxy solo desvía el tráfico cuando el contenedor nuevo responde 200 a GET /up. Si tu aplicación no expone ese endpoint, o devuelve un error mientras todavía arranca, la comprobación de salud nunca pasa y Kamal restaura el contenedor anterior.