Quitter Railway pour votre propre serveur
Suivez ça sur votre propre serveur. Commencer gratuitement, sans carte
Railway est pratique jusqu’au jour où la facture est plus salée que prévu, ou que vous voulez un serveur dans lequel vous pouvez entrer en SSH plutôt qu’un tableau de bord entre vous et la machine. Partir de Railway, c’est deux tâches distinctes : faire tourner le code et la configuration de votre application ailleurs, et sortir les données de la base Postgres gérée par Railway sans rien perdre et sans arrêter l’application plus longtemps qu’un changement de DNS ne l’exige. Aucune des deux n’est spécifique à Railway une fois qu’on voit la forme générale : récupérer la configuration, dumper la base, remonter la même chose sur un serveur que vous contrôlez, puis basculer le DNS.
Ce guide fait ça à la main d’abord, avec votre propre serveur et Docker Compose, puis couvre l’import en un clic qui lit un projet Railway directement et automatise presque tout ça.
Ce qu’il vous faut
- Un serveur. Un Hetzner CX23 (2 vCPU, 4 Go de RAM, actuellement 5,99 €/mois hors TVA) ou un droplet DigitalOcean de 2 Go (12 $US/mois) suffit pour la plupart des petites applications avec leur base Postgres.
- Un compte Railway avec un jeton API, et l’accès au CLI (
npm install -g @railway/cli, puisrailway login). - Le DNS de votre domaine, prêt à être repointé une fois le nouveau serveur opérationnel.
pg_dumpetpg_restoreinstallés localement, ou exécutés depuis un conteneur (les deux sont inclus dans l’image Docker officiellepostgres).
Étape 1 : voir ce qui tourne réellement
Avant d’exporter quoi que ce soit, liez le CLI au projet pour voir ses services et les variables exactes de chacun :
railway login
railway link
railway variable list
Ça affiche chaque variable que Railway a définie pour le service lié, y compris celles qu’il génère lui-même comme DATABASE_URL, RAILWAY_PRIVATE_DOMAIN, et tout ce que vous avez ajouté vous-même. Copiez cette sortie quelque part : c’est le moyen le plus rapide de récupérer chaque clé API, feature flag et secret au même endroit sans tout retaper depuis le tableau de bord.
Étape 2 : donner une adresse publique à la base de données
Le plugin Postgres de Railway n’écoute par défaut que sur le réseau privé de Railway ; DATABASE_URL pointe vers un nom d’hôte .railway.internal que votre machine ne peut pas atteindre. Pour la dumper depuis l’extérieur de Railway, ouvrez Settings → Networking du service Postgres et activez Public Networking, ce qui crée un proxy TCP et une nouvelle variable DATABASE_PUBLIC_URL à côté de la privée. Relistez les variables pour la récupérer :
railway variable list
Railway facture le trafic sortant qui passe par ce proxy, donc c’est un coût ponctuel pour la migration, pas quelque chose à laisser activé ensuite à moins d’en avoir besoin pour autre chose.
Étape 3 : dumper la base de données
Avec DATABASE_PUBLIC_URL en main, dumpez-la depuis votre machine (ou depuis le nouveau serveur, ce qui évite de tirer les données deux fois) :
pg_dump "$DATABASE_PUBLIC_URL" --format=custom --file=railway-export.dump
Le format custom (-Fc) compresse le dump et permet à pg_restore de paralléliser la restauration plus tard, ce qui compte dès que la base dépasse quelques centaines de mégaoctets. Gardez Railway actif pendant ce temps ; un dump ne touche en rien à la base en production, donc il n’y a pas encore d’interruption.
Étape 4 : préparer le nouveau serveur
Installez Docker sur le serveur de la même façon quel que soit le fournisseur :
curl -fsSL https://get.docker.com | sh
apt-get install -y docker-compose-plugin
Écrivez un docker-compose.yml avec Postgres, votre application, et Caddy pour le HTTPS :
services:
db:
image: postgres:18
restart: unless-stopped
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myapp
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
app:
build: .
restart: unless-stopped
env_file: .env
depends_on:
- db
expose:
- "3000"
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
depends_on:
- app
volumes:
postgres_data:
caddy_data:
caddy_config:
Si Railway construisait déjà votre application à partir d’un Dockerfile, réutilisez-le tel quel ; l’étape de build ne sait pas, et n’a pas besoin de savoir, quelle plateforme fait tourner l’image résultante. Si Railway la construisait sans Dockerfile (via sa propre détection Railpack/Nixpacks), il va falloir en écrire un maintenant. Le contenu exact dépend de votre langage, mais le principe reste celui décrit dans Déployer depuis un dépôt : installer les dépendances, builder, et lancer la commande de démarrage que votre application utilise déjà en développement.
Étape 5 : restaurer la base de données
Démarrez d’abord seulement la base, puis restaurez-y les données :
docker compose up -d db
docker compose exec -T db pg_restore --no-owner --no-acl -U myapp -d myapp < railway-export.dump
--no-owner et --no-acl sautent les instructions de rôles et de permissions propres à Railway qui n’existent pas sur ce serveur, puisque le dump a été fait depuis une base appartenant à un rôle différent de celui que vous venez de créer.
Étape 6 : reporter les variables d’environnement
Traduisez la sortie de railway variable list de l’étape 1 en un fichier .env pour le service app. La plupart se copie sans changement ; quelques valeurs doivent pointer vers la nouvelle configuration plutôt que vers celle de Railway :
DATABASE_URL=postgresql://myapp:changeme@db:5432/myapp
REDIS_URL=redis://redis:6379
# tout le reste de `railway variable list` que votre app lit directement
Si l’application utilisait Redis ou un autre add-on de Railway, ajoutez-le comme son propre service dans docker-compose.yml, de la même façon que db est défini, et pointez l’URL correspondante vers le nom de ce service plutôt que vers un nom d’hôte Railway.
Étape 7 : écrire le Caddyfile et passer en production
myapp.example.com {
reverse_proxy app:3000
}
Pointez l’enregistrement A du domaine vers le nouveau serveur, attendez qu’il se propage, puis démarrez tout :
docker compose up -d --build
docker compose logs -f caddy
Vous devriez voir Caddy obtenir un certificat et l’application répondre sur https://myapp.example.com. Comparez quelques pages ou réponses d’API avec le déploiement Railway encore actif avant de considérer que c’est terminé.
Étape 8 : basculer et fermer Railway
Une fois que le nouveau serveur sert du vrai trafic correctement pendant un jour ou deux, repointez toutes les références restantes (webhooks, URL d’API d’une app mobile, tout ce qui est codé en dur) et arrêtez le projet Railway. Gardez le fichier de dump quelques semaines avant de le supprimer.
Le raccourci : importer depuis Railway directement
Applications → Import de Railyard lit les projets Railway via un jeton API et construit un plan avant de créer quoi que ce soit, plutôt que de deviner. D’après le fonctionnement réel de l’import : il lit les services, environnements et variables de chaque projet via l’API propre de Railway, et pour chaque service il reprend le dépôt Git ou l’image exacte que Railway fait tourner, sa commande de démarrage quand elle est définie, ses domaines personnalisés, et ses variables, nettoyées de celles propres à Railway. Il détecte aussi quelles variables pointent vers un add-on Postgres, Redis, MongoDB ou MySQL d’après la forme de leurs URL, et propose de provisionner la base correspondante sur le nouveau serveur et d’y copier les données automatiquement, la même approche dump-puis-restauration-dans-une-base-fraîche que ci-dessus, sans que vous touchiez un terminal.
Une base de données sans adresse publique a toujours besoin que ce même interrupteur Public Networking soit activé côté Railway d’abord. Rien ne peut faire transiter le contenu d’une base sans que le proxy TCP ne la rende accessible quelque part.
Lancez l’import depuis la page de migration, collez un jeton API Railway, examinez le plan que Railyard affiche pour chaque service, et choisissez le serveur sur lequel le déployer. Voir Importer depuis une autre plateforme pour savoir ce qui est repris automatiquement par rapport à ce qu’il faut encore saisir à la main (l’API de Railway n’expose pas le contenu des fichiers secrets, par exemple), et Coûts d’hébergement si toute la raison de ce déménagement est de comparer ce que vous payez réellement à un serveur que vous provisionnez vous-même.
Dépannage
pg_dump n’arrive pas à se connecter, ou reste bloqué. Vérifiez que Public Networking est bien activé pour le service Postgres et que vous avez copié DATABASE_PUBLIC_URL, pas DATABASE_URL ; la privée pointe vers un nom d’hôte .railway.internal que votre machine ne peut absolument pas atteindre, ce qui se traduit généralement par un échec de résolution DNS plutôt qu’une connexion refusée.
pg_restore renvoie des erreurs sur des rôles ou permissions qui n’existent pas. Ajoutez --no-owner --no-acl à la commande de restauration, qui ignore les instructions de propriété et de droits liées aux noms de rôles internes de Railway.
L’application n’arrive pas à joindre la base après le basculement. Vérifiez que DATABASE_URL dans le nouveau .env pointe vers le nom du service Compose (db), pas vers localhost ou l’ancien nom d’hôte Railway ; à l’intérieur de Docker Compose, les services se joignent entre eux par leur nom sur le réseau partagé, pas par 127.0.0.1.
Le HTTPS n’est jamais émis sur le nouveau serveur. Le DNS du domaine pointe presque certainement encore vers Railway, ou ne s’est pas encore propagé. Vérifiez avec dig myapp.example.com et comparez avec l’IP du nouveau serveur avant de chercher le problème du côté de Caddy.
Manque de mémoire pendant la restauration d’un gros dump sur un petit serveur. pg_restore avec les réglages par défaut peut utiliser une mémoire étonnamment élevée sur un dump avec beaucoup d’index. Restaurez sans --jobs (en série, plus lent, moins de mémoire) sur tout ce qui a moins de 4 Go de RAM, ou agrandissez temporairement le serveur pour la restauration puis redescendez ensuite.
FAQ
Est-ce que ça marche si je n’utilise pas Postgres ? Le même principe s’applique à MySQL (mysqldump/mysql) et à Redis (redis-cli --rdb), même si les commandes exactes diffèrent. L’import de Railyard détecte aussi les add-ons Redis, MongoDB et MySQL de la même façon qu’il détecte Postgres.
Puis-je migrer progressivement, un service à la fois ? Oui. Rien n’oblige à déplacer tout un projet Railway d’un coup ; importez ou reconstruisez un service, vérifiez-le, puis passez au suivant.
Qu’arrive-t-il au stockage éphémère ou aux volumes de Railway ? Tout ce qui est écrit sur un volume Railway doit être copié séparément, généralement avec scp ou rsync depuis une session shell ponctuelle côté Railway avant de fermer le projet, puisque ni l’export de variables du CLI ni un dump de base de données ne touchent aux volumes du système de fichiers.
L’écart de prix vaut-il vraiment la migration ? Ça dépend entièrement de la taille et du trafic de l’application. Coûts d’hébergement et le vérificateur de facture Heroku sont faits pour rendre cette comparaison concrète plutôt qu’une supposition, même si le second porte le nom de Heroku spécifiquement.
Les parties qui font paraître ça risqué, surtout la base de données, sont aussi les plus mécaniques une fois qu’on l’a fait une fois : dumper, restaurer, vérifier, basculer le DNS. Tout le reste, c’est simplement faire tourner le même conteneur ailleurs que chez Railway.
Pourquoi les gens choisissent Railyard pour ça
- Votre propre compte infonuagique. Déployez sur DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, ou n'importe quel serveur Linux par SSH, facturé directement par votre fournisseur, sans majoration.
- Un prix fixe par équipe. L'offre gratuite est gratuite pour toujours : un serveur plus un serveur de base de données, trois applications, sans carte. Pro coûte 19 $ par mois pour jusqu'à cinq serveurs et un nombre illimité d'applications. Team coûte 49 $ par mois avec des serveurs illimités. Aucuns frais par application, par déploiement, par siège ou par gigaoctet.
- Des gabarits en un clic. Déployez des applications open source, comme des bases de données, des outils d'analyse et des outils de développement, sur votre propre serveur en un clic.
- Des bases de données gérées. Postgres, MySQL et Redis, avec des sauvegardes planifiées, vérifiées par restauration, et la récupération à un point dans le temps.
- Déploiement par push. Déployez depuis GitHub, GitLab ou la CLI, avec HTTPS automatique et des mises en production sans interruption.