← Blogue

Passer de Fly.io à votre propre serveur

Railyard

22 mai 2026 · 9 min de lecture

Suivez ça sur votre propre serveur. Commencer gratuitement, sans carte

Fly facture à l’usage, ce qui est difficile à prévoir, et « Fly Postgres » reste une base Postgres que vous opérez vous-même, juste sur les machines de Fly plutôt que les vôtres. Si vous avez déjà un Dockerfile qui construit et tourne sur Fly, vous avez presque tout ce qu’il faut pour le faire tourner ailleurs aussi. Ce guide déplace une application Fly existante, son environnement, ses secrets et ses données Postgres sur un seul serveur que vous possédez : Docker Compose, Caddy pour le HTTPS, une vraie tâche de sauvegarde, puis une bascule DNS sans fenêtre d’indisponibilité. Le raccourci à la fin utilise le propre importateur Fly de Railyard pour les parties qui n’ont pas besoin d’un dump et d’une restauration manuels.

Ce qu’il vous faut

  • Un serveur. Un Droplet Basic DigitalOcean à 2 vCPU et 2 Go de RAM fait tourner la plupart des petites applications avec une instance Postgres pour 18 $US/mois; montez à 4 Go pour 24 $US/mois si votre application fait du vrai travail de fond. N’importe quelle machine Ubuntu équivalente chez un autre fournisseur fonctionne de la même façon.
  • Un nom de domaine que vous pouvez repointer, idéalement celui déjà attaché à l’application Fly.
  • Le CLI flyctl, déjà authentifié contre le compte propriétaire de l’application (fly auth whoami devrait afficher votre compte, pas une erreur).

Étape 1 : faire l’inventaire de ce dont l’application Fly a vraiment besoin

Récupérez la config actuelle de l’application pour savoir ce que vous reproduisez, plutôt que de deviner :

fly config show -a your-fly-app

Vous devriez récupérer le même JSON que Fly déploie, incluant le bloc [http_service] ou [[services]] avec internal_port, le bloc [env] avec vos variables non secrètes, et tout [[mounts]] pour les volumes. Notez le port interne en particulier, c’est la seule valeur sur laquelle chaque autre service de ce guide doit s’accorder.

Listez les secrets par nom, puisque Fly ne vous en montre jamais les valeurs :

fly secrets list -a your-fly-app

Vous devriez voir un tableau de noms de secrets, de signatures et de statut de déploiement, pas les valeurs elles-mêmes. Récupérez les vraies valeurs d’où vous les avez mises à l’origine (un gestionnaire de mots de passe, vos secrets CI, un coéquipier), puisque c’est la seule chose que Fly ne peut vraiment pas vous redonner.

Étape 2 : provisionner le serveur et installer Docker

curl -fsSL https://get.docker.com | sh
docker compose version

Vous devriez voir une chaîne de version Compose v2.x. Pointez l’enregistrement A de votre domaine vers le nouveau serveur maintenant, puisque l’étape HTTPS plus tard en dépend :

dig +short app.example.com

Étape 3 : écrire le fichier Docker Compose

La plupart des applications Fly construisent déjà à partir d’un Dockerfile dans le dépôt, Fly en exige un (ou un buildpack qui en produit un) pour déployer du tout, alors la même image qui tourne sur les machines de Fly tourne ici aussi. Ajoutez Postgres et Caddy autour :

services:
  app:
    build: .
    restart: unless-stopped
    env_file: .env
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app_net

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      start_period: 10s
      retries: 20
    networks:
      - app_net

  caddy:
    image: caddy:2
    restart: unless-stopped
    depends_on:
      - app
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - app_net

networks:
  app_net:

volumes:
  postgres_data:
  caddy_data:
  caddy_config:

Construisez le .env à partir du bloc [env] que fly config show a affiché plus tôt, plus les valeurs de secrets que vous avez récupérées :

POSTGRES_PASSWORD=une-longue-chaine-aleatoire
DATABASE_URL=postgres://app:une-longue-chaine-aleatoire@db:5432/app
PORT=8080
# tout ce qui vient du bloc [env] de fly config show va ici aussi
# tout ce que fly secrets list a nommé va ici, avec sa vraie valeur

PORT devrait correspondre à l’internal_port de l’étape 1, puisque c’est le port sur lequel le code de votre application écoute vraiment, peu importe quelle plateforme le fait tourner.

Étape 4 : déplacer les données Postgres

Si l’application utilise le Postgres non géré de Fly (une application Postgres que vous avez déployée et attachée vous-même, le cas courant pour des applications qui tournent depuis un moment), ouvrez un proxy vers elle :

fly proxy 15432:5432 -a your-postgres-app

Dans un second terminal, dumpez la base à travers ce proxy :

pg_dump -Fc -h localhost -p 15432 -U postgres your_database -f fly-dump.pgdump

Vous devriez vous retrouver avec un fichier fly-dump.pgdump non vide; ls -lh fly-dump.pgdump devrait montrer une taille à peu près en ligne avec ce que vous attendez de vos données, pas une poignée d’octets.

Copiez-le sur le nouveau serveur et restaurez-le dans le conteneur db une fois la pile démarrée :

scp fly-dump.pgdump root@YOUR_SERVER_IP:/root/
docker compose cp /root/fly-dump.pgdump db:/tmp/fly-dump.pgdump
docker compose exec db pg_restore -U app -d app --no-owner --no-acl /tmp/fly-dump.pgdump

--no-owner --no-acl retirent les informations de rôle et de permission qui n’avaient de sens que sur le Postgres de Fly, pour que la restauration n’échoue pas en cherchant un rôle qui n’existe pas ici. Vous devriez voir pg_restore se terminer avec, au pire, quelques avertissements sur des objets ignorés pour la même raison, pas une erreur bloquante.

Si vous êtes plutôt sur le Managed Postgres plus récent de Fly, la commande proxy est fly mpg proxy YOUR_CLUSTER_ID --local-port 15432 et les détails de connexion (utilisateur, nom de base) viennent de fly mpg status plutôt que d’être postgres/le nom de votre application par défaut; les commandes pg_dump/pg_restore elles-mêmes sont identiques une fois passé le proxy.

Étape 5 : démarrer la pile et vérifier

docker compose up -d --build
docker compose logs -f app

Vous devriez voir les propres lignes de démarrage normales de votre application, les mêmes que vous verriez dans fly logs, se terminant par son écoute sur le port du .env. Confirmez que les données sont bien arrivées :

docker compose exec db psql -U app -d app -c "SELECT count(*) FROM your_main_table;"

Ce compte devrait correspondre à ce que vous voyiez sur Fly avant le dump, à quelques lignes écrites entre-temps près.

Étape 6 : écrire le Caddyfile et basculer le DNS

app.example.com {
	reverse_proxy app:8080
}

Démarrez Caddy et confirmez que le certificat s’émet (docker compose logs caddy) avant de toucher au DNS. Une fois que https://app.example.com répond correctement contre le nouveau serveur, sur un sous-domaine temporaire ou en modifiant votre /etc/hosts local pour tester, mettez à jour le vrai enregistrement A pour pointer vers l’IP du nouveau serveur. Fly continue de servir le sous-domaine propre à l’application pendant tout ce temps, puisque vous n’y avez rien touché, donc il n’y a pas de trou où ni l’un ni l’autre serveur ne répond. Une fois confirmé que le trafic arrive bien au nouveau serveur, mettez l’application Fly à zéro machine et, une fois sûr de ne plus en avoir besoin, supprimez-la.

Étape 7 : sauvegardes et mises à jour

Sauvegardez Postgres de la même façon que vous l’avez dumpé de Fly, mais sur un horaire cette fois :

#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%Y%m%d-%H%M%S)
mkdir -p backups
docker compose exec -T db pg_dump -U app -Fc app > "backups/app-db-$STAMP.pgdump"
find backups -name '*.pgdump' -mtime +14 -delete

Copiez backups/ hors du serveur sur la même tâche cron, vers une autre machine ou du stockage objet. Pour mettre à jour l’application elle-même, reconstruisez et recréez seulement ce conteneur :

docker compose build app
docker compose up -d app

Le raccourci : faites-le avec Railyard

L’importateur Fly de Railyard gère les parties de tout ça qui n’impliquent pas vos propres données : depuis Applications → New app → Import from Heroku / Render / Fly, choisissez Fly, collez un jeton depuis fly tokens create org, et choisissez l’application. Il récupère l’image exacte que Fly fait tourner (en utilisant votre jeton comme mot de passe de registre, donc rien ne se reconstruit depuis la source), les variables d’environnement et le port interne depuis la config de la machine, et les noms de vos secrets, vous en ressaisissez les valeurs puisque Fly ne les expose jamais à quoi que ce soit, y compris cet importateur. Les autres groupes de processus au-delà du principal ne sont pas encore copiés, ajoutez-les comme workers après coup, et les volumes démarrent vides, donc l’étape 4 ci-dessus (ou sa variante Managed Postgres) reste la façon dont les données elles-mêmes se déplacent; l’importateur lui-même ne touche pas du tout à Postgres.

https://app.railyard.run/deploy?repo=https://github.com/you/your-app

fonctionne aussi, pour le simple chemin de push Git une fois que l’importateur a géré les parties propres à Fly, ou si vous préférez le sauter complètement. Voyez Importer depuis une autre plateforme pour le portrait complet de ce que chaque plateforme source apporte, Migrer depuis Fly.io pour la correspondance détail par détail entre les concepts de Fly et ceux de Railyard, et Coûts d’hébergement si vous essayez aussi de déterminer ce que le nouveau serveur devrait vous coûter réellement par rapport à ce que Fly facturait.

Dépannage

pg_restore échoue sur un rôle ou une extension introuvable. C’est presque toujours une extension propre à Fly ou un rôle référencé dans le dump qui n’existe pas sur la destination. --no-owner --no-acl règle la plupart des cas; pour une extension vraiment manquante, installez-la dans l’image Postgres de destination ou retirez la ligne CREATE EXTENSION du dump avant de restaurer.

L’application démarre mais retourne immédiatement un 502 derrière Caddy. Vérifiez que PORT dans .env correspond à la fois à ce sur quoi votre application se lie réellement et à ce que la ligne reverse_proxy du Caddyfile pointe. Un décalage ici est la cause la plus courante, puisque Fly et une configuration Compose générique ne s’entendent pas toujours sur la façon dont le port est injecté.

Le certificat n’est jamais émis. dig +short app.example.com doit d’abord se résoudre vers le nouveau serveur. Si vous testez avant la vraie bascule, utilisez un sous-domaine de staging qui pointe déjà ici plutôt que d’attendre l’enregistrement de production.

Secrets manquants après l’import, ou l’application plante sur une valeur de config. L’API de Fly ne retourne jamais les valeurs des secrets, seulement les noms, alors c’est attendu : ressaisissez chacun d’où vous l’aviez stocké à l’origine, pas depuis l’import.

Manque de mémoire pendant pg_restore sur un petit serveur. Un droplet à 2 Go peut peiner à restaurer un gros dump en même temps qu’une application qui tourne. Arrêtez le conteneur app pendant la restauration (docker compose stop app) pour libérer la mémoire, puis redémarrez-le une fois pg_restore terminé.

Foire aux questions

Dois-je tout migrer d’un coup? Non. Déplacez d’abord la base de données et le processus principal, vérifiez, puis ajoutez tout groupe de processus secondaire comme services worker séparés une fois que vous avez confirmé que l’application principale fonctionne.

Qu’arrive-t-il au sous-domaine que Fly assigne automatiquement à chaque application? Rien, jusqu’à ce que vous supprimiez l’application Fly. Il continue de répondre jusqu’au moment où vous mettez l’application à zéro, ce qui est justement ce qui rend possible la bascule sans interruption : l’ancienne et la nouvelle adresse fonctionnent simultanément pendant que le DNS se propage.

Est-ce que ça fonctionne pour des applications utilisant le déploiement multi-région de Fly? Ce guide vous déplace vers un seul serveur dans une seule région. Si vous avez vraiment besoin de plusieurs régions, reproduisez cette configuration une fois par région derrière votre propre répartition de charge, il n’y a pas d’équivalent en une commande ici à la répartition automatique entre régions de Fly.

Est-ce que le Managed Postgres de Fly est assez différent pour avoir ses propres étapes? Seulement la commande proxy et le nom d’utilisateur par défaut, fly mpg proxy au lieu de fly proxy, et les identifiants depuis fly mpg status plutôt que le nom de l’application. pg_dump et pg_restore fonctionnent exactement pareil une fois connecté.

Les deux chemins sortent votre application et ses données du modèle de facturation de Fly pour les poser sur un serveur dont vous voyez la vraie spec et la vraie facture, les étapes manuelles si vous voulez le contrôle complet de la bascule, l’importateur si vous préférez le laisser récupérer les 80 % faciles pour vous.

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.

Importez l'application directement depuis Fly

L'importateur Fly de Railyard récupère la même image, le même port et les mêmes variables d'environnement avec votre jeton, pour que vous n'ayez qu'à ressaisir les secrets.

Offre gratuite, sans carte, et 14 jours de Pro pour chaque nouvelle équipe. Prix fixe par équipe.