De Scalingo à mon VPS : migration d'une app Rails 8 avec Kamal

Publié le 04 mai 2026
Les étapes clés du site internet
kamal logo
En une soirée, j’ai migré mon portfolio depuis Scalingo (25€/mois) vers mon VPS Hostinger déjà payé, en utilisant Kamal — l’outil de déploiement officiel intégré à Rails 8. Voici comment, pourquoi, et ce que j’en retiens.

Pourquoi migrer ?

Mon portfolio tournait sur Scalingo depuis plusieurs mois. Le service est excellent : déploiement par git push, scaling automatique, monitoring intégré. Mais pour une app sans utilisateur, avec quelques visiteurs par jour, le rapport coût/usage devenait disproportionné : 25€ par mois pour héberger un portfolio, soit 300€ par an.

En parallèle, j’avais un VPS KVM 4 chez Hostinger payé deux ans d’avance. La décision était évidente : rapatrier l’app sur ce VPS et économiser le coût Scalingo pendant toute l’année restante.

Restait à choisir comment déployer.
Pourquoi Kamal plutôt qu’autre chose ?

J’ai considéré trois options :
  • Docker Compose + Traefik manuel : c’est ce que j’avais bricolé sur le VPS auparavant. Ça marche, mais chaque mise à jour devient pénible — il faut SSH, pull, rebuild, restart, en faisant attention aux certs Let’s Encrypt.
  • Coolify : une plateforme PaaS auto-hébergée façon Heroku-like. Très bien pour gérer plusieurs projets via une UI web, mais overkill pour un seul portfolio, et ça consomme 2-3 Go de RAM rien que pour la plateforme elle-même.
  • Kamal 2 : l’outil de déploiement officiel intégré à Rails 8 depuis 2024, créé par 37signals (Basecamp, HEY). Pas d’UI, juste une CLI. Build, push, deploy zero-downtime, rollback, certs Let’s Encrypt automatiques.
J’ai choisi Kamal pour trois raisons :
  • C’est intégré à Rails 8 nativement
  • C’est simple par design (pas de couche superflue).
  • C’est la convention de l’écosystème Rails aujourd’hui. Apprendre Kamal sert pour tous mes futurs projets.

Le setup en bref

Kamal fonctionne sur un principe minimaliste : tu décris ton infra dans un fichier config/deploy.yml, tu mets tes secrets dans .kamal/secrets, et tu lances kamal deploy depuis ta machine locale. Kamal SSH sur le serveur, build l’image Docker (en local ou à distance), la push vers un registry, puis orchestre un rolling deploy.
L’architecture finale ressemble à ça :
  • VPS Hostinger (Ubuntu 24.04) — l’hôte.
  • kamal-proxy — reverse proxy minimaliste qui occupe les ports 80/443 et gère les certificats Let’s Encrypt automatiquement.
  • Container Rails 8 — l’app, sur le port interne 3000.
  • Container Postgres 17 — la base, accessible uniquement depuis le réseau Docker interne.
  • GHCR (GitHub Container Registry) — pour stocker les images Docker, gratuit et illimité avec un compte GitHub.

Le deploy.yml tient en 50 lignes et déclare tout : les serveurs, le builder, le proxy, les variables d’environnement, l’accessoire Postgres.
Les étapes clés de la migration
1. Audit et nettoyage du VPS

2. Sauvegarde du dump Postgres depuis Scalingo
Scalingo permet de télécharger un backup Postgres depuis l’interface web — un fichier .tar.gz contenant un dump au format custom pg_dump -Fc. Je l’ai téléchargé en local avant toute manipulation, et gardé une copie séparée.
Règle d’or : avoir au moins deux copies du dump avant de toucher à quoi que ce soit.

3. Configuration de Kamal
Le deploy.yml définit toute l’infrastructure. Voici une version simplifiée pour mon cas :
text
Copier
service: 
image:

servers:
  web:
    - IP_VPS

proxy:
  ssl: true
  hosts:
    - nomdedomaine.fr
    - www.nomdedomaine.fr
  app_port: 3000

registry:
  server: ghcr.io
  username: GitHub profile
  password:
    - KAMAL_REGISTRY_PASSWORD

builder:
  arch: amd64
  remote: ssh://root@IP_VPS

env:
  secret:
    - RAILS_MASTER_KEY
    - POSTGRES_PASSWORD
    - DATABASE_URL
  clear:
    DB_HOST: user-db
    POSTGRES_USER: user
    POSTGRES_DB: user_production
    DOMAIN: nomdedomaine.fr
    RAILS_LOG_TO_STDOUT: "true"
    RAILS_SERVE_STATIC_FILES: "true"

ssh:
  user: user

accessories:
  db:
    image: postgres:17
    host: IP_VPS
    port: "127.0.0.1:5432:5432"
    env:
      clear:
        POSTGRES_USER: user
        POSTGRES_DB: user_production
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data

À côté, le fichier .kamal/secrets contient les valeurs sensibles, hors du repo Git :

text
Copier
KAMAL_REGISTRY_PASSWORD=ghp_xxxxx
RAILS_MASTER_KEY=$(cat config/master.key)
POSTGRES_PASSWORD=monMotDePasseGeneré
DATABASE_URL=postgres://user:monMotDePasseGeneré@user-db:5432/user_production

Le builder remote est un détail important : sans Docker Desktop installé localement, Kamal délègue le build au VPS lui-même via SSH. Ça évite d’avoir Docker en permanence sur ma machine, et le build profite des 4 vCPU du serveur.

4. Bascule DNS et activation SSL

Le résultat
Après quelques heures de travail, le portfolio tourne sur le VPS avec :
  • HTTPS valide via Let’s Encrypt, renouvellement automatique.
  • ~10 ms de temps de réponse Rails, nettement mieux qu’avant.
  • Déploiement en une commande : git push puis kamal deploy, ~2 minutes, zero-downtime.
  • Rollback en 30 secondes avec kamal app rollback.
  • ~300€/an d’économies.

Ce que je retiens
Kamal n’est pas magique. C’est essentiellement une CLI bien pensée autour de Docker et SSH, qui automatise ce qu’on ferait à la main avec Compose. Mais cette automatisation change tout : les déploiements deviennent boring, dans le bon sens. Plus de stress, plus de scripts maison, plus d’oubli.
Pour une app personnelle ou un side-project Rails 8, la combinaison VPS + Kamal est aujourd’hui imbattable en rapport simplicité/contrôle/coût

Thème

Les étapes clés du site internet

Date de publication

04 mai 2026

Dernière mise à jour

04 mai 2026