SSD Nodes Learn 8GB de RAM — $66/an
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-02

Docker Compose : démarrer automatiquement au redémarrage

Faites redémarrer vos services Docker Compose après un reboot : politiques restart, limite de on-failure et unité systemd si l’ordre de démarrage compte.

La réponse courte

Les services Docker Compose démarrent au démarrage lorsque deux conditions sont réunies. Le daemon Docker doit être activé comme service système, et chaque service du fichier doit avoir une politique de redémarrage définie sur unless-stopped ou always. Ajoutez restart: unless-stopped à chaque service, exécutez docker compose up -d une fois, puis les conteneurs redémarreront automatiquement après un redémarrage du système. Rien d’autre n’est nécessaire dans le cas courant.

Vous avez besoin d’une unité systemd uniquement lorsque l’ordre de démarrage est important : une stack qui dépend d’un disque monté, d’une interface VPN ou d’un partage réseau qui n’est pas prêt au moment où le daemon Docker démarre. Ce cas est réel, et la deuxième partie de ce guide le couvre. Si vous découvrez encore les définitions de services et les volumes, commencez par les bases de Docker Compose sur un VPS, puis revenez ici.

Définir la politique de redémarrage dans compose.yaml

La politique se définit sur une ligne par service. Il n’existe pas de paramètre global. Si vous oubliez un service, il reste arrêté après le redémarrage, tandis que le reste de la stack démarre.

services:
  app:
    image: nginx:1.27
    restart: unless-stopped
    ports:
      - "8080:80"
  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: change-me
    volumes:
      - dbdata:/var/lib/postgresql/data

volumes:
  dbdata:

Appliquez la modification, puis relisez la politique du conteneur en cours d’exécution :

docker compose up -d
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app)

Cette commande affiche unless-stopped. Si elle affiche no, le fichier a été modifié, mais le conteneur n’a jamais été recréé.

Il s’agit de la cause d’échec la plus fréquente. La politique de redémarrage est stockée dans le conteneur, pas dans le fichier YAML. Modifier compose.yaml ne change rien pour un conteneur qui existe déjà. docker compose restart n’est pas utile non plus, car cette commande arrête et redémarre le même objet conteneur sans modifier sa configuration. Seul docker compose up -d compare le fichier aux conteneurs en cours d’exécution, détecte la modification de la politique et recrée les conteneurs.

Pour un conteneur que vous ne souhaitez pas recréer maintenant, modifiez la politique directement :

docker update --restart unless-stopped my-container

Modifiez également le fichier YAML. docker update modifie le conteneur en cours d’exécution, et la prochaine commande docker compose up -d relira le fichier et rétablira l’ancienne valeur.

Ce que fait réellement chaque valeur de redémarrage

Docker définit quatre valeurs. La différence entre elles apparaît uniquement lorsque la machine redémarre ou que le daemon est redémarré.

  • no est la valeur par défaut. Le conteneur n’est jamais redémarré automatiquement, quelles que soient les circonstances.
  • always redémarre le conteneur dès qu’il s’arrête. Si vous l’avez arrêté manuellement, il redémarre quand même au prochain démarrage du daemon Docker. C’est souvent surprenant : un conteneur que vous avez volontairement arrêté la semaine dernière fonctionne de nouveau après un redémarrage.
  • unless-stopped se comporte comme always, sauf qu’un conteneur arrêté manuellement reste arrêté après le redémarrage du daemon. Utilisez cette valeur pour un service que vous arrêtez parfois pour effectuer une maintenance.
  • on-failure redémarre le conteneur uniquement lorsque celui-ci se termine avec un code de sortie différent de zéro. Vous pouvez limiter le nombre de tentatives, comme dans restart: on-failure:3.

Pour une stack qui doit simplement être disponible lorsque le serveur est disponible, unless-stopped est la valeur par défaut appropriée. Choisissez always uniquement lorsque vous voulez empêcher qu’un conteneur reste arrêté.

Pourquoi redémarrer : on-failure ne survit pas à un redémarrage

Beaucoup choisissent on-failure parce que cette option semble prudente, puis constatent que tous les conteneurs sont arrêtés après le premier redémarrage. La raison tient à sa définition. on-failure réagit à une seule situation : le processus du conteneur se termine avec un code d’erreur.

Un redémarrage n’est pas une erreur. Lorsque l’hôte s’arrête, systemd arrête docker.service, et le daemon arrête délibérément chaque conteneur. Le conteneur n’a pas échoué. La policy n’a donc rien à traiter. Lors du redémarrage, le daemon examine les conteneurs qu’il doit relancer. Un conteneur on-failure arrêté correctement n’en fait pas partie. Il reste dans l’état exited.

Vous pouvez le vérifier directement. Définissez restart: on-failure sur un service, exécutez docker compose up -d, redémarrez, puis exécutez :

docker compose ps -a

Le service apparaît avec l’état Exited et un statut similaire à Exited (0) 2 minutes ago. Rien n’est défaillant et aucune erreur n’est enregistrée. C’est ce qui rend le diagnostic difficile. La policy a fait exactement ce qui est prévu.

on-failure reste utile. Cette option convient à un conteneur qui exécute un job et peut subir un crash, lorsque vous voulez limiter le nombre de tentatives et éviter une boucle de redémarrage. Elle ne convient pas pour maintenir un service de longue durée actif après un redémarrage.

Les policies de redémarrage ne fonctionnent que si le service Docker démarre au boot

Les policies de redémarrage sont appliquées par le daemon Docker. Si le daemon ne démarre pas, rien ne les applique. Vérifiez-le :

systemctl is-enabled docker
systemctl is-enabled containerd

Les deux commandes doivent afficher enabled. Les paquets du dépôt officiel de Docker les activent lors de l'installation. Sur un serveur neuf, ce test réussit donc généralement. Si l'une des deux commandes affiche disabled, corrigez le problème :

sudo systemctl enable --now docker containerd

Un piège mérite d'être compris. Ubuntu fournit également docker.socket, qui démarre le daemon à la demande dès qu'un processus communique avec l'API Docker. Vous pouvez voir que docker.socket est activé, penser que le daemon est pris en charge, puis désactiver docker.service pour économiser de la mémoire. Au démarrage, aucun processus n'appelle l'API. Le socket n'est donc jamais utilisé, le daemon ne démarre jamais et aucun conteneur ne démarre avant votre première commande docker. L'activation par socket ne remplace pas l'activation de docker.service.

Quand une unité systemd est la meilleure solution

Les politiques de redémarrage ne gèrent pas l’ordre de démarrage par rapport au reste du système. Le daemon démarre et lance vos conteneurs dès que possible. Si votre stack monte un répertoire avec bind mount depuis un volume distinct, un partage NFS (network file system) ou un disque chiffré, les conteneurs peuvent démarrer avant que ce chemin existe. Docker crée alors sans problème un répertoire vide au point de montage et démarre le conteneur avec ce répertoire. Votre base de données démarre donc sans données.

Créez une unité systemd dans l’un des cas suivants. La stack a besoin qu’un montage, une interface VPN ou une autre unité soit prête auparavant. Vous voulez que systemctl stop myapp et systemctl start myapp fonctionnent comme pour tous les autres services du serveur. Vous voulez aussi que la stack soit arrêtée proprement lors de l’arrêt du système, au lieu d’être tuée en même temps que le daemon. Si les unités systemd sont nouvelles pour vous, écrire un service et un timer systemd décrit plus en détail le format des fichiers.

Écrire l’unité systemd

Placez la stack dans un chemin fixe, en dehors d’un répertoire personnel. /srv/myapp convient bien, car une unité qui s’exécute avant toute connexion n’a aucune raison de lire /home.

Créez /etc/systemd/system/myapp.service :

[Unit]
Description=myapp docker compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
RequiresMountsFor=/srv/myapp/data

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/srv/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target

Activez-la et démarrez-la :

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.service

Une unité fonctionnelle affiche Active: active (exited). Cela semble incorrect la première fois. C’est normal : Type=oneshot avec RemainAfterExit=yes signifie que l’unité a exécuté sa commande, que la commande s’est terminée et que systemd conserve l’unité comme active afin que ExecStop s’exécute à l’arrêt.

Chaque ligne a une fonction précise. Requires=docker.service signifie que l’unité échoue immédiatement au lieu d’exécuter docker compose sur un socket indisponible. After= définit l’ordre, car Requires= seul ne le fait pas. RequiresMountsFor= demande à systemd de charger l’unité mount correspondant à ce chemin et d’attendre qu’elle soit disponible. C’est précisément l’intérêt d’utiliser une unité plutôt qu’une restart policy. TimeoutStartSec=0 empêche systemd d’arrêter le job de démarrage pendant le téléchargement d’une image volumineuse.

À propos de la combinaison de ces deux mécanismes. La documentation de Docker déconseille de mélanger les restart policies avec un gestionnaire de processus de l’hôte. Cet avertissement concerne un gestionnaire de processus qui supervise directement le processus du conteneur et le redémarre pendant que le daemon tente de faire la même chose. Une unité Type=oneshot ne supervise rien. Vous pouvez donc conserver restart: unless-stopped dans le fichier compose avec cette unité, et c’est ce qu’il faut faire. systemd gère l’ordre au démarrage, tandis que le daemon gère un conteneur qui se termine de manière inattendue au milieu de la nuit.

Vérifier avec un vrai redémarrage

Rien ne remplace le test réel. systemctl restart docker ne vérifie pas l’ordre de montage, et docker compose down suivi de docker compose up -d ne vérifie rien concernant le démarrage.

sudo reboot

Attendez, reconnectez-vous, puis vérifiez dans cet ordre :

uptime
systemctl is-active docker
docker compose ps

uptime confirme que vous consultez une machine qui a réellement redémarré. docker compose ps, exécuté depuis le répertoire de la stack, doit afficher chaque service avec l’état running et un uptime proche de celui de la machine. Un service affichant Exited est celui qu’il faut examiner.

Si un élément n’a pas démarré, le journal du daemon couvre la période du démarrage :

journalctl -u docker.service -b --no-pager | tail -50

Pour une stack gérée par une unit, journalctl -u myapp.service -b --no-pager affiche la sortie exacte de docker compose au démarrage, notamment en cas d’échec du pull d’une image ou d’absence du fichier .env.

Ce qui empêche discrètement le démarrage automatique

Les conteneurs créés avec docker compose run n'utilisent jamais la politique de redémarrage définie dans le fichier. Compose les traite comme des conteneurs temporaires. Si un service semble ignorer sa politique, vérifiez s'il a été démarré avec run au lieu de up.

Un chemin relatif dans un volume ou dans une entrée env_file est résolu par rapport au répertoire du fichier Compose. Cela fonctionne depuis votre shell et depuis une unit qui définit WorkingDirectory. Cela échoue depuis une unit qui ne le définit pas, car le répertoire de travail est alors /.

Docker rootless est un cas particulier. Le daemon s'exécute comme un service utilisateur, et un service utilisateur s'arrête lorsque la dernière session de cet utilisateur se termine. Activez-le pour l'utilisateur et autorisez-le à continuer de s'exécuter même lorsqu'aucun utilisateur n'est connecté :

systemctl --user enable docker
sudo loginctl enable-linger $USER

Sans enable-linger, le daemon rootless s'arrête lorsque vous vous déconnectez, et les conteneurs s'arrêtent avec lui. Cela ressemble exactement à une politique de redémarrage défaillante.

Dernier point. Les mises à jour de sécurité automatiques peuvent redémarrer un serveur à une heure fixe. C'est utile uniquement si votre stack redémarre automatiquement. La configuration sur une nouvelle machine fait partie des tâches à effectuer pendant la première heure, avec les dix premières minutes sur un nouveau VPS.

FAQ

Quelle est la différence entre restart: always et restart: unless-stopped ?

Les deux redémarrent le conteneur lorsqu’il s’arrête de lui-même. La différence apparaît lorsque vous arrêtez un conteneur manuellement. Avec always, le conteneur redémarre au prochain démarrage du daemon Docker. Un redémarrage du système annule donc votre arrêt manuel. Avec unless-stopped, le daemon mémorise que le conteneur a été arrêté volontairement et le laisse arrêté. Utilisez unless-stopped, sauf si vous voulez spécifiquement qu’un conteneur reste arrêté.

J’ai ajouté restart: unless-stopped, mais le conteneur ne démarre toujours pas après un redémarrage. Pourquoi ?

La policy est enregistrée sur le conteneur, pas dans le fichier. La modification du YAML ne met pas à jour un conteneur existant. Exécutez docker compose up -d pour que Compose le recrée, puis vérifiez avec docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app). Si cette commande affiche no, le conteneur existait déjà avant votre modification. L’autre cause courante est que docker.service n’est pas activé. Vous pouvez le vérifier avec systemctl is-enabled docker.

Ai-je besoin d’une unité systemd si j’utilise déjà des restart policies ?

En général, non. Une restart policy suffit pour une stack qui ne dépend que du réseau, ce qui est le cas de la plupart des stacks. Ajoutez une unité lorsque les conteneurs dépendent d’un élément qui n’est pas prêt au démarrage du daemon Docker, par exemple un disque externe, un volume chiffré, un partage NFS ou une interface VPN. L’unité permet de définir l’ordre de démarrage avec After= et RequiresMountsFor=, ce qu’une restart policy ne permet pas d’exprimer.

Comment arrêter définitivement une stack sans qu’elle redémarre au prochain reboot ?

Avec unless-stopped, docker compose stop suffit, car un conteneur arrêté manuellement ne redémarre pas lorsque le daemon redémarre. Avec always, un simple arrêt ne suffit pas et le conteneur redémarre après un reboot. Exécutez docker compose down, qui supprime les conteneurs, ou modifiez d’abord la policy avec docker update --restart no my-container. Si une unité systemd gère la stack, exécutez également sudo systemctl disable myapp.service, sinon l’unité la redémarrera.