Retour au blog

Migration d'infrastructure WalidLab 🔧

Migration de l'infrastructure de mon serveur depuis Docker + Traefik vers Dokploy

Migration d'infrastructure : Docker + Traefik vers Dokploy

Introduction

AprÚs plusieurs mois à gérer manuellement mon infrastructure Docker avec Traefik, j'ai décidé de franchir le pas et de migrer vers Dokploy, une plateforme d'orchestration self-hosted qui promet de simplifier drastiquement les déploiements tout en conservant le contrÎle total de l'infrastructure.

Cet article détaille cette migration complÚte, les choix architecturaux effectués, et le retour sur investissement concret d'une telle transition.

Le contexte initial

Mon infrastructure reposait sur une stack classique mais fonctionnelle :

  • Docker pour la conteneurisation
  • Traefik comme reverse proxy et gestionnaire SSL
  • Docker Registry privĂ© pour les images custom
  • Des fichiers docker-compose.yml dispersĂ©s sur le serveur
  • DĂ©ploiements manuels via SSH et git pull

Cette approche fonctionnait, mais présentait plusieurs limitations :

  • Chaque dĂ©ploiement nĂ©cessitait une connexion SSH manuelle
  • La gestion des labels Traefik devenait verbeuse et rĂ©pĂ©titive
  • Aucun systĂšme de rollback simple en cas d'erreur
  • Absence de centralisation pour la gestion des variables d'environnement
  • Pas d'intĂ©gration CI/CD native

Pourquoi Dokploy ?

Dokploy se positionne comme une alternative self-hosted à des solutions comme Vercel ou Netlify, mais pour l'ensemble de la stack applicative. Les promesses sont alléchantes :

  • Interface web moderne pour gĂ©rer l'ensemble de l'infrastructure
  • DĂ©ploiement continu automatique depuis Git (GitHub, GitLab, Gitea)
  • Traefik intĂ©grĂ© et prĂ©-configurĂ©
  • Gestion SSL automatisĂ©e via Let's Encrypt
  • Support natif de Docker Compose
  • Registry Docker intĂ©grĂ©
  • Logs et monitoring centralisĂ©s

L'aspect self-hosted était crucial : je souhaitais conserver le contrÎle total de mes données et de mon infrastructure, sans dépendre d'un service tiers.

Architecture de la solution

Infrastructure physique

L'ensemble de l'infrastructure tourne sur un VPS unique derriĂšre Cloudflare :

Internet
  ↓
Cloudflare (Proxy + CDN + WAF)
  ↓
VPS (Dokploy + Applications)
  ↓
dokploy-network (réseau Docker privé)

Couche de sécurité

J'ai mis en place une architecture en couches pour la sécurité :

Interface d'administration (Dokploy UI)

  • Accessible uniquement via VPN (ZeroTier)
  • Aucune exposition publique de l'interface
  • Authentication forte avec mots de passe complexes

Webhooks Git

  • ExposĂ©s publiquement mais authentifiĂ©s par token
  • Configuration Traefik en PathPrefix pour isoler uniquement /api/deploy/webhook/*
  • Rate limiting appliquĂ© par Traefik

Applications

  • Exposition publique via domaines dĂ©diĂ©s
  • SSL/TLS automatique avec Let's Encrypt
  • Headers de sĂ©curitĂ© configurĂ©s (HSTS, CSP, etc.)

Cloudflare Workers pour la résilience

J'ai implémenté deux Workers Cloudflare pour gérer intelligemment le trafic :

Worker Maintenance (temporaire)
Pendant la phase de migration, un Worker gÚre trois scénarios :

  • Applications dĂ©jĂ  migrĂ©es → passthrough vers le serveur
  • Applications en cours de migration → page de maintenance Ă©lĂ©gante
  • Domaines non configurĂ©s → page 404 personnalisĂ©e
const migratedApps = ['dokploy.walidlab.dev', 'app1.walidlab.dev'];
const configuredApps = ['app2.walidlab.dev', 'app3.walidlab.dev'];

if (migratedApps.includes(url.hostname)) {
  return fetch(request); // Passthrough
}
if (configuredApps.includes(url.hostname)) {
  return new Response(maintenanceHTML, ...); // Maintenance
}
return new Response(error404HTML, ...); // 404

Cette approche permet une migration progressive sans interruption de service perceptible pour les utilisateurs.

Worker 404 permanent
Avec un wildcard DNS (*.walidlab.dev), tous les sous-domaines pointent vers mon serveur. Le Worker 404 filtre en amont les requĂȘtes vers des domaines non configurĂ©s, rĂ©duisant la charge sur le serveur et amĂ©liorant la sĂ©curitĂ© en Ă©vitant les scans automatisĂ©s.

Avantage collatéral : mon serveur ne voit jamais le trafic malveillant ou les tentatives de scan de domaines aléatoires.

Le protocole ACME et Let's Encrypt : comprendre le fonctionnement

La migration a été l'occasion d'approfondir ma compréhension du protocole ACME (Automatic Certificate Management Environment) utilisé par Let's Encrypt.

Le challenge HTTP-01 en détail

Contrairement à une idée reçue, le challenge HTTP n'est pas une simple validation passive. Voici le flow exact :

  1. Génération locale de la paire de clés : Traefik génÚre la clé privée du certificat en local. Cette clé ne quitte jamais le serveur.

  2. Création d'une demande : Un CSR (Certificate Signing Request) est créé, contenant la clé publique et les informations du domaine.

  3. Authentification ACME : Traefik s'authentifie auprÚs de Let's Encrypt via une clé de compte ACME dédiée, distincte de la clé du certificat.

  4. Challenge : Let's Encrypt génÚre un token aléatoire et demande à Traefik de l'exposer sur http://domain/.well-known/acme-challenge/TOKEN

  5. Polling actif : Traefik notifie Let's Encrypt que le challenge est prĂȘt. Ce n'est pas Let's Encrypt qui dĂ©cide quand vĂ©rifier, mais Traefik qui signale sa disponibilitĂ©.

  6. Validation : Let's Encrypt effectue une requĂȘte HTTP depuis ses serveurs pour vĂ©rifier la prĂ©sence du token.

  7. Émission : Si la validation rĂ©ussit, Let's Encrypt signe le certificat avec sa propre CA et le retourne Ă  Traefik.

  8. Stockage : Le certificat est stocké dans acme.json avec la clé privée.

Un point crucial : la clé privée ne transite jamais sur le réseau. Seul le certificat public (signé) est transmis par Let's Encrypt.

Renouvellement automatique

Traefik vĂ©rifie quotidiennement l'expiration des certificats. À J-30, il relance automatiquement le processus de renouvellement avec le mĂȘme mĂ©canisme, assurant une continuitĂ© de service sans intervention manuelle.

Migration : méthodologie et défis

Préparation

Avant toute migration, j'ai établi un inventaire complet :

  • 13 applications Ă  migrer
  • 2 bases de donnĂ©es partagĂ©es (MongoDB et MariaDB)
  • Multiples services interconnectĂ©s (architecture microservices)
  • Volumes Docker existants Ă  prĂ©server

Approche progressive

J'ai opté pour une migration progressive application par application :

  1. Application pilote : Migration d'une application non critique pour valider le processus
  2. Configuration des services partagés : Déploiement des bases de données en tant que services indépendants
  3. Migration des services principaux : API, frontends, workers
  4. Tests de communication inter-services : Validation du routage réseau
  5. Finalisation : Migration des services annexes

Défis rencontrés

Communication inter-conteneurs en Docker Swarm

Dokploy utilise Docker Swarm en sous-couche. Les conteneurs ont des noms complexes incluant des suffixes dynamiques (ex: app.1.h1vzkys2lq01g0icrjnsj37jw), mais Docker Swarm maintient des alias DNS stables basés sur le nom du service.

Leçon apprise : toujours référencer les services par leur nom simple, pas par le nom complet du conteneur.

Variables d'environnement au build time

Avec Vite.js, les variables d'environnement doivent ĂȘtre disponibles au moment du build, pas au runtime. La solution avec Dokploy :

ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL
RUN npm run build

Dokploy transforme automatiquement les variables d'environnement de l'UI en --build-arg lors du build Docker.

Debugging d'une erreur 502 mystérieuse

L'erreur la plus chronophage concernait des 502 aléatoires sur certains endpoints. AprÚs élimination systématique de toutes les hypothÚses (Traefik, DNS, CORS, SSL), l'analyse des logs Traefik a révélé :

"OriginStatus": 502,
"Duration": 45000000

Le 502 provenait de l'API elle-mĂȘme, qui effectuait un fetch vers un autre microservice avec une variable d'environnement mal configurĂ©e. Le timeout de 45 secondes correspondait au timeout par dĂ©faut de Node.js.

Solution : configuration correcte des noms de services Docker Swarm dans les variables d'environnement.

Retour sur investissement

Gains quantifiables

Temps de déploiement

  • Avant : ~5 minutes par application (SSH, git pull, docker-compose, vĂ©rifications)
  • AprĂšs : 0 minute (automatique sur git push)
  • ROI : 100% du temps de dĂ©ploiement Ă©conomisĂ©

Gestion des certificats SSL

  • Avant : VĂ©rifications manuelles pĂ©riodiques, renouvellements parfois oubliĂ©s
  • AprĂšs : ComplĂštement automatisĂ© avec monitoring intĂ©grĂ©
  • ROI : Élimination du risque d'expiration de certificat

Rollback en cas d'erreur

  • Avant : git revert + rebuild + redĂ©ploiement manuel (~10-15 minutes)
  • AprĂšs : 1 clic dans l'interface Dokploy (~30 secondes)
  • ROI : RĂ©duction drastique du MTTR (Mean Time To Recovery)

Gains qualitatifs

Réduction de la charge cognitive

  • Plus besoin de mĂ©moriser les commandes Docker
  • Plus besoin de connaĂźtre l'emplacement exact des compose files
  • Interface unifiĂ©e pour tous les services

Amélioration de la collaboration

  • PossibilitĂ© d'embarquer des personnes non-techniques sur les dĂ©ploiements
  • Logs centralisĂ©s et accessibles sans SSH
  • Historique des dĂ©ploiements avec possibilitĂ© de rollback

Sécurité renforcée

  • Interface d'administration non exposĂ©e publiquement
  • Webhooks avec authentification forte
  • Filtrage du trafic malveillant en amont via Cloudflare Workers

Coûts

Temps de migration

  • Setup initial : ~2 heures
  • Migration de 13 applications : ~4 heures
  • Debug et optimisations : ~2 heures
  • Total : ~8 heures sur un weekend

Courbe d'apprentissage

  • ComprĂ©hension de l'architecture Dokploy : ~1 heure
  • MaĂźtrise des spĂ©cificitĂ©s Docker Swarm : ~1 heure
  • Total : ~2 heures

Maintenance continue

  • Avant : ~2 heures par semaine (dĂ©ploiements, vĂ©rifications, corrections)
  • AprĂšs : ~15 minutes par semaine (surveillance, mise Ă  jour Dokploy)
  • Économie : ~1h45 par semaine, soit ~91 heures par an

Architecture finale

Stack technique

┌─────────────────────────────────────────┐
│ Cloudflare (Edge)                       │
│ ├─ Workers (Maintenance + 404)          │
│ ├─ WAF + DDoS Protection                │
│ └─ CDN + Cache                          │
└────────────┬────────────────────────────┘
             │
             ▌
┌─────────────────────────────────────────┐
│ VPS Infrastructure                      │
│                                         │
│ ┌─────────────────────────────────┐   │
│ │ Dokploy (Management Layer)      │   │
│ │ ├─ UI (ZeroTier only)           │   │
│ │ ├─ Webhooks (public, auth)      │   │
│ │ └─ Docker Registry              │   │
│ └─────────────────────────────────┘   │
│                                         │
│ ┌─────────────────────────────────┐   │
│ │ Traefik (Reverse Proxy)         │   │
│ │ ├─ SSL/TLS (Let's Encrypt)      │   │
│ │ ├─ Routing                      │   │
│ │ └─ Middlewares                  │   │
│ └─────────────────────────────────┘   │
│                                         │
│ ┌─────────────────────────────────┐   │
│ │ Applications                    │   │
│ │ ├─ APIs (Node.js, Python)       │   │
│ │ ├─ Frontends (React, Vue)       │   │
│ │ └─ Workers (Background jobs)    │   │
│ └─────────────────────────────────┘   │
│                                         │
│ ┌─────────────────────────────────┐   │
│ │ Data Layer                      │   │
│ │ ├─ MongoDB (shared)             │   │
│ │ ├─ MariaDB (shared)             │   │
│ │ └─ Redis (caching)              │   │
│ └─────────────────────────────────┘   │
│                                         │
│ Network: dokploy-network (overlay)     │
└─────────────────────────────────────────┘

Patterns de communication

Inter-services
Les services communiquent via le réseau Docker overlay dokploy-network en utilisant les noms de services comme hostnames. Docker Swarm maintient la résolution DNS automatiquement.

// Configuration d'un service
const API_URL = process.env.API_URL; // http://service-name:port

Base de données partagées
Les bases de données sont déployées comme services indépendants avec des volumes persistants. Chaque application configure sa propre base de données sur l'instance partagée.

# Application 1
MONGODB_URI: mongodb://shared-mongodb:27017/app1_db

# Application 2
MONGODB_URI: mongodb://shared-mongodb:27017/app2_db

Recommandations et bonnes pratiques

Nommage des services

Adoptez une convention de nommage cohérente pour éviter les conflits DNS :

# Évitez les noms gĂ©nĂ©riques
api ❌
db ❌

# Préférez des noms descriptifs
project-api ✅
project-database ✅
project-worker ✅

Variables d'environnement

Build time vs Runtime
Distinguez clairement les variables nécessaires au build (préfixées VITE_, REACT_APP_, etc.) et celles utilisées au runtime.

Pour les frameworks frontend, considérez l'injection de configuration au runtime via un fichier env.js généré par l'entrypoint Docker pour éviter de rebuilder à chaque changement d'environnement.

Sécurité

N'exposez jamais les services internes
Les bases de donnĂ©es, Redis, et autres services d'infrastructure ne doivent jamais ĂȘtre exposĂ©s publiquement. Utilisez uniquement le rĂ©seau Docker interne.

Utilisez des secrets forts
Dokploy stocke les variables d'environnement en clair dans sa base de données. Utilisez des mots de passe complexes et unique pour chaque service.

Limitez l'accĂšs Ă  l'UI
L'interface Dokploy donne un contrĂŽle total sur l'infrastructure. Restreignez son accĂšs via VPN ou IP whitelisting.

Monitoring et observabilité

Activez les logs d'accĂšs Traefik
Ils sont précieux pour le debugging et la compréhension du trafic :

accessLog:
  filePath: "/var/log/traefik/access.log"
  format: json

Centralisez les logs applicatifs
Dokploy expose les logs via son UI, mais pour une observabilité avancée, considérez une stack Loki + Grafana.

Limitations et considérations

Dokploy n'est pas adapté à tous les cas

Évitez Dokploy pour :

  • Infrastructures multi-serveurs complexes (prĂ©fĂ©rez Kubernetes)
  • Besoins d'orchestration avancĂ©e (auto-scaling horizontal, placement constraints complexes)
  • Équipes nĂ©cessitant GitOps strict avec approval workflows (prĂ©fĂ©rez ArgoCD)

Dokploy excelle pour :

  • Projets personnels et side-projects
  • Petites Ă©quipes (<10 personnes)
  • Applications monolithiques ou microservices simples
  • Budgets limitĂ©s (alternative aux PaaS payants)

Vendor lock-in relatif

Bien que Dokploy soit open-source, migrer vers une autre solution nécessite de reconfigurer manuellement chaque service. Conservez une documentation de votre architecture.

Maturité du projet

Dokploy est un projet relativement jeune. Attendez-vous à des bugs occasionnels et à des fonctionnalités manquantes. La communauté est active, mais le support n'est pas au niveau d'un produit commercial.

Conclusion

La migration vers Dokploy représente un investissement initial de quelques heures, largement compensé par les gains de productivité quotidiens. Pour un développeur gérant une infrastructure personnelle ou de petites équipes souhaitant s'affranchir des coûts récurrents des PaaS, Dokploy offre un excellent compromis entre simplicité d'utilisation et contrÎle de l'infrastructure.

L'automatisation du déploiement continu, couplée à une gestion SSL transparente et une interface moderne, transforme radicalement l'expérience de gestion d'infrastructure. Le simple fait de pouvoir déployer via un git push sans se soucier des détails techniques sous-jacents libÚre un temps considérable pour se concentrer sur le développement de fonctionnalités.

Au-delà de l'outillage, cette migration a été l'occasion d'approfondir ma compréhension des mécanismes fondamentaux du web moderne : protocole ACME, architecture edge computing avec les Workers, patterns de communication dans Docker Swarm. Cette compréhension en profondeur permet de faire des choix architecturaux éclairés et de débugger efficacement lorsque des problÚmes surviennent.

Pour ceux qui hésitent encore : si vous gérez manuellement Docker + Traefik et que vous déployez réguliÚrement, Dokploy vous fera gagner un temps précieux. L'investissement initial est minime, et le retour sur investissement se mesure dÚs les premiÚres semaines.


Stack finale : Dokploy + Docker Swarm + Traefik + Let's Encrypt + Cloudflare Workers
Temps de migration : 8 heures
ROI estimé : ~91 heures économisées par an
Recommandation : ⭐⭐⭐⭐⭐

Partager :