Objectif : un serveur de redondance pour une prod managée par Coolify, capable de reprendre le service si le serveur principal tombe — mais sans que ce standby soit lui-même piloté par Coolify (pas d’orchestration distante, juste une copie qu’on démarre à la main). Le plan initial clonait la conf Caddy du serveur source… sauf que la source ne tourne plus sous Caddy depuis qu’elle est passée sous Coolify/Traefik. Il fallait revoir l’approche. Bonne surprise : c’est plus simple qu’attendu.
Ce que Coolify écrit sur disque
Coolify ne garde pas ses déploiements dans une base opaque : pour chaque service/app, il rend les fichiers sur disque côté serveur, dans /data/coolify/{services,applications}/<uuid>/ :
- un
docker-compose.ymlcomplet, avec des labels Traefik 100 % standards ; - un
.envavec les valeurs résolues (clés,DATABASE_URL,BASE_URL, SMTP… en clair).
Les labels n’ont rien de magique :
- traefik.enable=true
- 'traefik.http.routers.https-xxx.rule=Host(`analytics.example.fr`)'
- traefik.http.routers.https-xxx.tls.certresolver=letsencrypt
- traefik.http.routers.https-xxx.tls=true
Coolify ne fait que générer du Traefik standard. Donc n’importe quel Traefik — y compris un Traefik standalone que je gère moi-même — ramasse ces labels tels quels, route le bon
Host(...)et émet le cert, sans réécrire un seul compose.
Le mirror : rsync + Traefik standalone
Le standby se résume à :
rsync -a --delete root@source:/data/coolify/{services,applications}/ ~/mirror/— récupère composes +.env; tout nouveau projet déployé sur la source apparaît automatiquement à la sync suivante.- Un Traefik standalone (hors Coolify) avec les mêmes entrypoints (
:80/:443), un resolver nomméletsencrypt, le provider Docker et un réseaucoolify(docker network create coolify). - Images déjà servies par un registry mirror local →
docker compose pullinstantané.
Au moment de la bascule : docker compose up les stacks, et Traefik fait le reste. Les certs LE s’émettent dès que le DNS pointe sur le standby.
Le piège : les données ne se rsync pas à chaud
La seule chose qui n’est pas du copier-coller, ce sont les volumes de bases de données. rsync d’un répertoire de données Postgres/ClickHouse vivant = copie incohérente, donc potentiellement corrompue au restore. Pour les données, le bon outil reste le dump logique (pg_dumpall, ClickHouse FORMAT Native) ou un snapshot de volume à l’arrêt — jamais une copie brute d’un datastore en cours d’écriture.
Définitions et routage : copiables tels quels. Données stateful : dumpées, jamais rsync’d à chaud. C’est la ligne de partage de tout mirror de prod.
Lessons learned
- Coolify (et la plupart des PaaS Docker) écrivent des composes +
.envrésolus sur disque. Un standby n’a pas besoin du PaaS : il a besoin des fichiers que le PaaS a déjà rendus.rsync+docker compose upsuffit. - Les labels Traefik générés sont standards. Un Traefik standalone configuré avec le même nom de resolver route les stacks miroir sans aucune réécriture. La techno de routage est portable, pas verrouillée par le PaaS.
- Sépare nettement définitions et données. Compose/env/labels → rsync. Bases de données → dumps logiques. Rsync d’un volume DB vivant est un piège à corruption silencieuse.
- Un mirror auto-suivi vaut mieux qu’un mirror câblé à la main.
rsync --deletedes dossiers du PaaS fait que les nouveaux services suivent tout seuls ; seul un nouveau type de donnée (fichiers hors-DB, datastore exotique) demande une ligne de config.
#selfhosted #devops #docker #coolify #traefik #highavailability