Déploiement11 min de lecture

Déployer des applications web avec Kamal sur un VPS

Kamal (anciennement MRSK), développé par 37signals, déploie des applications conteneurisées sur un ou plusieurs VPS depuis votre machine locale, sans orchestrateur lourd. En version 2 depuis septembre 2024, il remplace Traefik par son propre proxy (kamal-proxy) et centralise la gestion des secrets dans `.kamal/secrets`. La commande `kamal deploy` coordonne build Docker, push vers un registre et bascule zero-downtime en une passe — sur un VPS unique comme sur un cluster de cinquante serveurs.

Pourquoi Kamal plutôt que Kubernetes pour déployer des applications web sur un VPS ?

Kubernetes résout des problèmes de coordination à grande échelle — découverte de service, autoscaling horizontal, namespaces multi-équipes — qui n'existent pas sur un VPS unique ou un petit cluster. Son plan de contrôle lui-même consomme entre 2 et 4 Go de RAM avant d'avoir lancé une seule application. Kamal occupe un terrain différent : il prend votre Dockerfile, construit l'image localement ou sur le serveur, la pousse vers un registre, l'exécute sur vos serveurs via SSH et bascule le trafic sans interruption grâce à kamal-proxy. Toute la configuration tient dans un fichier config/deploy.yml versionné avec votre code. Pas de control plane à maintenir, pas de certificats d'API à renouveler, pas de YAML interminable réparti sur dix ressources. Vous conservez la simplicité opérationnelle d'un VPS — accès SSH direct, docker ps lisible, logs dans un fichier — tout en disposant d'un workflow de déploiement professionnel avec rollback instantané, health checks et HTTPS automatique.

Ce que Kamal v2 vous apporte

  • Déploiements zero-downtime — kamal-proxy attend que les health checks passent sur le nouveau conteneur avant de basculer le trafic, et draine les requêtes en vol sur l'ancien
  • Une seule commandekamal deploy enchaîne build, push vers le registre, déploiement SSH et vérification sans intervention manuelle
  • HTTPS automatique Let's Encrypt — kamal-proxy gère le renouvellement des certificats TLS ; aucune configuration Certbot séparée
  • Rollback instantanékamal rollback [VERSION] repointe le proxy sur une image déjà présente sur le serveur en quelques secondes
  • Gestion des secrets structurée.kamal/secrets supporte la lecture depuis 1Password, Bitwarden ou des variables d'environnement, sans stocker de valeurs en clair dans le dépôt
  • Multi-serveurs et multi-rôles natifs — web, workers Sidekiq, accessoires Postgres ou Redis décrits dans un seul fichier, déployés en parallèle
  • Multi-applications sur un seul VPS — depuis Kamal 2, plusieurs applications partagent un même kamal-proxy sans conflit de configuration
  • Compatible toute stack — Rails, Django, Node.js, Go, PHP : Kamal ne présuppose qu'un Dockerfile et un registre d'images

Prérequis chiffrés avant de déployer avec Kamal

Côté VPS, Kamal exige Ubuntu 22.04 ou 24.04 (ou toute distribution Linux avec Docker 20.10+), un accès SSH par clé (pas de mot de passe), et au minimum 2 vCPU et 2 Go de RAM pour une application web standard avec sa base de données. Kamal peut installer Docker lui-même lors du premier kamal setup, mais le compte SSH doit disposer des droits sudo. Un port 80 et 443 ouverts en entrée et un enregistrement DNS A pointant vers l'IP du VPS sont indispensables avant d'activer le SSL. Côté machine locale, deux options existent : installer la gem Ruby (gem install kamal, requiert Ruby 3.1+) ou utiliser l'image Docker officielle. La version courante est la 2.12.0 (juin 2026). Préparez enfin un registre de conteneurs — Docker Hub, GitHub Container Registry ou un registre privé — ainsi que ses identifiants.

Kamal v1 vs Kamal v2 : ce qui a changé

Kamal 2, sorti en septembre 2024 (bundlé par défaut dans Rails 8, sorti en novembre 2024), remplace Traefik par kamal-proxy, un reverse proxy développé en interne par 37signals. Le changement est structurel : Traefik est déclaratif (on lui soumet une configuration et il converge), alors que Kamal est impératif. La version 1 devait interroger l'API de Traefik en boucle pour savoir si le déploiement avait abouti — une source de raceconditions. Avec kamal-proxy, les commandes sont directes et synchrones. Côté configuration, le bloc traefik: disparaît de deploy.yml ; il est remplacé par proxy: avec les clés host, ssl et app_port. Les secrets migrent de .env vers .kamal/secrets, un fichier shell évalué qui peut appeler des CLI externes (op read, bw get). La commande kamal upgrade détecte une configuration v1 et propose un plan de migration automatisé. Enfin, Kamal 2 introduit le déploiement de plusieurs applications sur un même proxy, le mode maintenance (kamal app pause) et le support expérimental des déploiements canary.

Installation et premier déploiement avec Kamal v2

01

Installer Kamal sur votre machine locale

Exécutez gem install kamal (Ruby 3.1+ requis) ou, si vous préférez éviter Ruby, utilisez l'alias Docker : alias kamal='docker run -it --rm -v "${PWD}:/workdir" -v "${SSH_AUTH_SOCK}:/ssh-agent" -e SSH_AUTH_SOCK=/ssh-agent -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/basecamp/kamal:latest'. Vérifiez l'installation avec kamal version — la version courante est 2.12.0.

02

Initialiser la configuration dans votre projet

Dans le dossier racine du projet, lancez kamal init. Kamal génère config/deploy.yml et .kamal/secrets. Renseignez dans deploy.yml : le nom du service (service: monapp), l'image (image: votreuser/monapp), la liste des serveurs (servers: web: - 203.0.113.10), et le registre (registry: server: ghcr.io ou omis pour Docker Hub).

03

Configurer les secrets et variables d'environnement

Ajoutez .kamal/secrets à votre .gitignore. Dans ce fichier, déclarez vos secrets sous forme de variables shell : KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD (lues depuis l'environnement local) ou DB_PASSWORD=$(op read op://vault/monapp/db-password) (depuis 1Password). Dans config/deploy.yml, référencez-les sous env.secret: pour les valeurs chiffrées et env.clear: pour les variables non sensibles comme RAILS_ENV=production.

04

Configurer le proxy et le SSL

Dans config/deploy.yml, ajoutez la section proxy : proxy: host: app.votre-domaine.com ssl: true app_port: 3000. Kamal-proxy obtiendra automatiquement un certificat Let's Encrypt via ACME HTTP-01. Assurez-vous que l'enregistrement DNS A pointe déjà vers l'IP du VPS avant cette étape — le défi ACME échoue sinon.

05

Provisionner le serveur (une seule fois)

Lancez kamal setup. Kamal se connecte en SSH, installe Docker si absent, authentifie le registre, démarre kamal-proxy et déploie la première version de l'application. Cette commande est l'unique étape d'amorçage : elle configure le serveur de A à Z. En cas de serveur déjà équipé, kamal setup détecte Docker existant et ne réinstalle pas.

06

Déployer les mises à jour suivantes

À chaque itération, exécutez kamal deploy. Kamal construit l'image (ou la récupère si elle existe déjà dans le cache), la pousse vers le registre, démarre un nouveau conteneur en parallèle de l'ancien, attend que le health check passe (par défaut GET /up), bascule kamal-proxy vers le nouveau conteneur, draine les connexions en cours et stoppe l'ancien. L'opération est visible en temps réel dans le terminal.

07

Vérifier l'état et consulter les logs

Après déploiement : kamal app details affiche la version en cours sur chaque serveur, kamal app logs -f suit les logs en temps réel, kamal app exec 'bin/rails console' ouvre une console dans le conteneur en production. Pour voir l'état du proxy : kamal proxy details.

08

Gérer les accessoires (base de données, cache)

Déclarez Postgres sous la clé accessories: dans deploy.yml : image, port, volumes, variables. kamal accessory boot db démarre le service sur le bon serveur. Les accessoires ne passent pas par kamal-proxy — ils sont joints directement par l'application via les variables d'environnement. Cette approche garde la stack entière décrite dans un seul fichier versionné.

Configuration multi-serveurs et déploiements parallèles

Kamal déploie vers tous les serveurs d'un rôle en parallèle par défaut. Pour un cluster de serveurs web, listez leurs IPs sous servers: web:. Pour un déploiement progressif (rolling), ajoutez boot: limit: 2 wait: 10 — Kamal déploiera sur 2 serveurs à la fois avec 10 secondes entre chaque vague. Les rôles permettent de différencier les serveurs : sous servers: déclarez web: (serveurs HTTP) et workers: avec une commande spécifique comme bundle exec sidekiq. Chaque rôle peut avoir ses propres serveurs, secrets et variables. Un seul kamal-proxy tourne sur le serveur désigné primary (le premier de la liste web) — les autres serveurs n'ont que le conteneur applicatif. Pour plusieurs applications sur un même VPS, chacune déclare son propre service: et host: dans son deploy.yml ; kamal-proxy les distingue par hostname et route les requêtes sans configuration additionnelle.

Variables d'environnement et secrets — bonnes pratiques

La séparation entre variables claires et secrets est explicite dans Kamal 2. Dans deploy.yml, les variables non sensibles vont sous env: clear: (elles apparaissent dans les logs et l'inspection de conteneur), et les secrets sous env: secret: — leur valeur est lue depuis .kamal/secrets au moment du déploiement et injectée dans le conteneur sans jamais transiter en clair dans une commande shell visible. Chaque rôle (web, workers, accessoires) doit lister explicitement les secrets qu'il utilise ; un secret dans .kamal/secrets n'est pas automatiquement propagé à tous les conteneurs. La commande kamal secrets print affiche les valeurs résolues pour vérifier que la lecture depuis un gestionnaire de mots de passe fonctionne correctement avant un déploiement. Pour les environnements multiples (staging, production), .kamal/secrets.staging et .kamal/secrets.production coexistent ; le fichier .kamal/secrets-common porte les valeurs partagées.

Si un déploiement introduit une régression, n'attendez pas le prochain cycle de build : exécutez kamal rollback [VERSION] pour repointer kamal-proxy instantanément vers une image précédente déjà présente sur le VPS. Listez les versions disponibles avec kamal app images. Le rollback ne reconstruit rien — il repointe le proxy en quelques secondes. En complément, kamal app exec 'commande' permet de lancer des migrations ou une console dans le conteneur actif sans ouvrir de session SSH manuelle.

HTTPS automatique avec kamal-proxy et Let's Encrypt

Kamal-proxy gère le cycle de vie TLS complet : il écoute sur le port 80, répond aux défis ACME HTTP-01 de Let's Encrypt, obtient le certificat, le stocke dans un volume Docker sur le serveur et le renouvelle automatiquement avant expiration. La seule précondition est que le nom d'hôte déclaré dans proxy: host: resolve bien vers l'IP du VPS au moment du premier déploiement — le défi ACME est synchrone et bloque le démarrage si le DNS n'est pas propagé. Sur des serveurs multiples hébergeant plusieurs applications, chaque application a son propre host: ; kamal-proxy route par Server Name Indication (SNI) et gère un certificat distinct par domaine. Pour les domaines qui ne nécessitent pas de TLS (environnements internes, staging sans domaine public), il suffit de ne pas inclure ssl: true dans la section proxy: — le proxy répond alors en HTTP sur le port 80.

Dépannage — erreurs fréquentes lors du déploiement avec Kamal

SSH connection timeout : vérifiez que l'IP du serveur est joignable (ssh -i votre_cle [email protected]) et que le pare-feu autorise le port 22. L'agent SSH doit être actif (eval $(ssh-agent) && ssh-add). Target failed to become healthy : le health check par défaut frappe GET /up — si votre application ne répond pas sur ce chemin, déclarez proxy: healthcheck: path: /health dans deploy.yml. Vérifiez aussi que app_port: correspond au port que le conteneur écoute réellement. Registry authentication error : kamal registry login puis relancez ; en CI, vérifiez que la variable KAMAL_REGISTRY_PASSWORD est bien exportée avant kamal deploy. Port conflict sur le serveur : si un processus externe occupe le port 80 ou 443, kamal-proxy ne peut pas démarrer. Identifiez-le avec ss -tlnp | grep -E '80|443' et arrêtez-le. Kamal setup échoue sur l'installation de Docker : le compte SSH doit avoir les droits sudo. Si l'installation automatique est refusée par la politique système, installez Docker manuellement et relancez kamal setup — il détecte Docker déjà présent et passe à l'étape suivante.

Intégrer Kamal dans un pipeline CI/CD GitHub Actions

Le fichier de workflow GitHub Actions typique pour Kamal 2 s'articule en deux jobs : un job de test (exécuté sur chaque push) et un job de déploiement conditionnel (déclenché sur push vers main ou publication d'une release). Dans le job de déploiement, installez Ruby et la gem Kamal, puis lancez kamal deploy avec les secrets injectés depuis GitHub Secrets. L'essentiel du fichier .github/workflows/deploy.yml : le job déploiement dépend du job test (needs: test), configure les variables d'environnement (KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}), installe Kamal avec gem install kamal -v 2.12.0 pour une version épinglée, puis exécute kamal deploy. L'agent SSH est configuré via webfactory/[email protected] avec la clé privée stockée dans les secrets GitHub. Chaque déploiement est ainsi traçable dans l'onglet Actions, avec les logs complets et la possibilité de le déclencher manuellement via workflow_dispatch.

Kamal v1 vs Kamal v2 — récapitulatif des différences

Kamal v1Kamal v2
ProxyTraefik (déclaratif, polling API)kamal-proxy (impératif, commandes directes)
Secrets.env à la racine du projet.kamal/secrets (shell évalué, gestionnaires de mots de passe)
SSLGéré par Traefik via ACMEGéré par kamal-proxy (Let's Encrypt intégré)
Multi-appsNon supporté nativementNatif : plusieurs apps par serveur, un seul proxy
Upgrade`kamal upgrade` détecte et migre la config v1
Config proxy dans deploy.ymlBloc `traefik:`Bloc `proxy:` avec `host`, `ssl`, `app_port`

Kamal sur un VPS ServOrbit — de la commande au domaine en orbite

Un VPS Cloud ServOrbit sous Ubuntu 24.04 répond à tous les prérequis de Kamal dès la livraison : accès SSH par clé, réseau 1 Gbit/s et IP dédiée. Le workflow type : créez un enregistrement DNS A pointant app.votre-domaine.com vers l'IP du VPS, lancez kamal setup depuis votre machine locale — Kamal installe Docker, démarre kamal-proxy, obtient le certificat Let's Encrypt et déploie votre application en une passe. Dès lors, chaque kamal deploy depuis votre terminal ou votre pipeline CI applique la mise à jour en zero-downtime. Pour héberger plusieurs projets sur un même VPS, chacun avec son propre domaine et son propre certificat, ajoutez une application dans un second deploy.yml pointant vers le même serveur — kamal-proxy route par hostname sans reconfiguration. La facturation reste celle du VPS, sans surcoût lié au déploiement.

Pilotez vos déploiements Kamal sur un VPS Cloud ServOrbit

Provisionnez un VPS Cloud avec le template Déploiement et accès SSH par clé : Kamal y installe Docker et déploie votre application en zero-downtime dès la première commande.

Besoin d'aide ?

Parcourez notre centre d'aide et notre FAQ, ou contactez notre équipe — rappel, WhatsApp ou e-mail. Support en français, anglais et arabe.

Écrire sur WhatsApps'ouvre dans un nouvel onglet