Aller au contenu
Administration Linux medium

Reboot et arrêt Linux : shutdown, systemctl

45 min de lecture

Arrêter ou redémarrer un système Linux semble trivial, jusqu'au jour où un reboot sec coupe une transaction base de données, une session rsync, ou votre propre connexion SSH sans retour possible. Les systèmes modernes exposent plusieurs commandes (shutdown, reboot, poweroff, systemctl) qui ont des comportements proches mais pas identiques, et systemd les intègre toutes dans un modèle de targets qui remplace les anciens runlevels. Ce guide pose le minimum à savoir pour choisir la bonne commande, planifier une maintenance proprement, et ne jamais se retrouver bloqué en mode dégradé.

  • Choisir entre shutdown, reboot, poweroff et systemctl selon le contexte
  • Planifier un arrêt ou un redémarrage en prévenant les sessions actives
  • Annuler un shutdown programmé avant qu'il ne démarre
  • Comprendre la correspondance runlevels SysV ↔ targets systemd, et pourquoi elle est à sens unique
  • Distinguer isolate (maintenant) de set-default (au prochain démarrage)
  • Basculer en mode rescue sans perdre l'accès à un serveur distant
  • Rendre le journal persistant pour que journalctl -b -1 serve le jour de l'incident
  • Réinitialiser un mot de passe root perdu via le GRUB

Trois scénarios concrets motivent la maîtrise de ces commandes :

  • Maintenance programmée, vous devez rebooter après l'installation d'un kernel ou d'une mise à jour majeure. Prévenir les utilisateurs, laisser le temps aux services de terminer proprement, annuler si quelqu'un objecte.
  • Intervention urgente, un service est bloqué, les commandes ne répondent plus, il faut rebooter sans casser le filesystem.
  • Récupération, mot de passe root perdu, /etc/fstab cassé, système qui ne monte pas /. Passer par le mode rescue plutôt qu'un live CD chaque fois que possible.

C'est une compétence attendue en LFCS (domaine System Operations) et RHCSA (Operate running systems).

  • Un shell avec droits sudo ou root
  • Un serveur Linux moderne (systemd : Ubuntu 16.04+, Debian 8+, RHEL 7+, Rocky, Fedora)
  • Pour les manipulations rescue/GRUB : accès console physique ou virtuelle, SSH ne suffit pas quand le système est dégradé

Les runlevels sont des niveaux d'exécution numériques hérités d'Unix System V. Vous les croiserez encore dans la doc et sur certains systèmes legacy.

RunlevelRôle
0Arrêt complet (shutdown)
1Mono-utilisateur (maintenance)
2Multi-utilisateur sans réseau (variable)
3Multi-utilisateur avec réseau (console)
5Multi-utilisateur avec interface graphique
6Redémarrage

Le runlevel par défaut était décrit dans /etc/inittab et chaque niveau avait ses scripts sous /etc/rc<N>.d/ (S* pour démarrer, K* pour arrêter un service).

Avec systemd, les runlevels sont remplacés par des targets plus expressifs et composables. Chaque target regroupe des unités (services, sockets, mounts, timers) et peut dépendre d'autres targets.

Cette correspondance n'est pas une table de conversion inventée par la documentation : elle est inscrite dans le système, sous forme de liens symboliques que vous pouvez lire vous-même.

Fenêtre de terminal
ls -l /usr/lib/systemd/system/runlevel*.target # RHEL, AlmaLinux, Rocky
ls -l /lib/systemd/system/runlevel*.target # Debian, Ubuntu
runlevel0.target -> poweroff.target
runlevel1.target -> rescue.target
runlevel2.target -> multi-user.target
runlevel3.target -> multi-user.target
runlevel4.target -> multi-user.target
runlevel5.target -> graphical.target
runlevel6.target -> reboot.target

Sept liens, mais seulement cinq cibles distinctes : les runlevels 2, 3 et 4 pointent tous sur multi-user.target. Cette correspondance à sens unique est la leçon importante. Sous SysVinit, passer du runlevel 2 au runlevel 3 changeait réellement l'état de la machine ; sous systemd, c'est strictement la même cible. Le runlevel n'est plus un mécanisme, c'est une couche de compatibilité conservée pour que les vieux scripts et les vieilles habitudes continuent de fonctionner. Corollaire pratique : init 3 ne « descend » pas depuis une session graphique vers un mode console différent de init 2, les deux font exactement la même chose.

La cible par défaut est celle que systemd atteint automatiquement à chaque démarrage. Deux commandes suffisent à la lire et à l'écrire, et il est important de comprendre qu'elles ne manipulent qu'un lien symbolique :

Fenêtre de terminal
systemctl get-default
multi-user.target
Fenêtre de terminal
sudo systemctl set-default multi-user.target
Removed '/etc/systemd/system/default.target'.
Created symlink '/etc/systemd/system/default.target' → '/usr/lib/systemd/system/multi-user.target'.

La sortie révèle le mécanisme complet : default.target dans /etc/systemd/system/ est un lien vers la cible souhaitée. Vous pouvez d'ailleurs vérifier l'état courant sans passer par systemctl, avec un simple ls -l /etc/systemd/system/default.target.

systemctl isolate démarre une cible et arrête tout ce qui n'en dépend pas. C'est ce second effet, souvent passé sous silence, qui en fait une commande à manier avec précaution.

Fenêtre de terminal
sudo systemctl isolate multi-user.target # arrête l'interface graphique

Après la bascule, runlevel affiche deux valeurs, le niveau précédent puis le niveau courant, ce qui permet de constater le changement :

5 3

Point capital : isolate ne modifie pas la cible par défaut. Un systemctl get-default juste après la bascule renvoie toujours l'ancienne valeur, et le prochain redémarrage repartira dessus. Les deux commandes répondent à deux besoins distincts, que ce tableau sépare :

BesoinCommandeEffet immédiatSurvit au redémarrage
Changer l'état maintenantsystemctl isolate <cible>ouinon
Changer l'état au prochain bootsystemctl set-default <cible>nonoui
Les deuxles deux commandesouioui

Toutes les cibles ne sont pas isolables. La propriété AllowIsolate le dit :

Fenêtre de terminal
systemctl show -p AllowIsolate --value graphical.target

Les cibles qui représentent un état complet du système (multi-user, graphical, rescue, emergency) répondent yes. Les cibles qui ne sont que des jalons intermédiaires (basic, sysinit, network-online) répondent no : les isoler laisserait la machine dans un état incohérent, systemd refuse donc la commande.

Plusieurs commandes, un seul but : couper proprement.

shutdown prévient les utilisateurs connectés et laisse le temps aux services de terminer. C'est la commande à privilégier en production.

Fenêtre de terminal
# arrêt immédiat
sudo shutdown -h now
# arrêt dans 10 minutes
sudo shutdown -h +10
# arrêt programmé avec message aux utilisateurs
sudo shutdown -h +5 "Maintenance : patch kernel"
# arrêt à une heure précise (format 24h)
sudo shutdown -h 23:00

Pour annuler un arrêt programmé tant qu'il n'a pas démarré :

Fenêtre de terminal
sudo shutdown -c
Fenêtre de terminal
sudo poweroff

Équivalent à shutdown -h now + coupure explicite de l'alimentation. Utile sur serveur physique pour être sûr que la machine est vraiment éteinte.

halt, arrêt sans forcément couper l'alimentation

Section intitulée « halt, arrêt sans forcément couper l'alimentation »
Fenêtre de terminal
sudo halt

Historique, moins utilisé aujourd'hui. Sur matériel récent avec ACPI, le comportement est équivalent à poweroff.

Fenêtre de terminal
sudo systemctl poweroff

La forme systemd, équivalente à poweroff sur un système moderne. À connaître pour la cohérence avec le reste de l'écosystème systemd.

Commandes legacy encore supportées via la compatibilité SysV. À connaître pour comprendre les scripts anciens, pas à utiliser au quotidien sur un système systemd.

Les mêmes outils, avec des options différentes.

Fenêtre de terminal
sudo reboot

Fonctionne sur toutes les distributions. Termine les processus, démonte les systèmes de fichiers, puis redémarre.

Fenêtre de terminal
sudo shutdown -r now # redémarrage immédiat
sudo shutdown -r +5 "mise à jour" # dans 5 minutes, avec message
sudo shutdown -c # annuler

La version à privilégier quand d'autres utilisateurs peuvent être connectés.

Fenêtre de terminal
sudo systemctl reboot

La forme systemd, équivalente à reboot. Cohérente avec systemctl poweroff, systemctl rescue, etc.

Legacy SysV, même fonction que reboot.

Une cible par défaut mal réglée est un défaut silencieux, et c'est ce qui explique qu'elle traîne des mois sur des machines en production. Sur un serveur sans interface graphique dont la cible par défaut est graphical.target, le démarrage se passe... normalement :

runlevel : N 5
get-default : graphical.target
is-system-running : running
unités en échec : 0

Aucune erreur, aucune unité en échec, le système se déclare running. La cause tient à une seule ligne dans la définition de la cible :

Fenêtre de terminal
systemctl cat graphical.target
[Unit]
Description=Graphical Interface
Requires=multi-user.target
Wants=display-manager.service
After=multi-user.target display-manager.service
AllowIsolate=yes

graphical.target veut (Wants=) le gestionnaire de session, il ne l'exige pas (Requires=). Or Wants= est une dépendance faible : si l'unité est absente ou échoue, la cible est quand même considérée comme atteinte. Sur une machine où aucun paquet graphique n'est installé, display-manager.service n'existe tout simplement pas, et personne n'est prévenu.

Ce n'est pas un cas théorique : Ubuntu Server 24.04 est livré avec graphical.target comme cible par défaut, alors que l'installation ne contient ni gdm3 ni ubuntu-desktop. La machine démarre en runlevel 5 sans le moindre paquet d'interface.

L'impact réel est faible sur une image serveur minimale, puisque rien de graphique n'est là pour être démarré. Il devient concret dès que des paquets tirent une dépendance graphique par accident : le serveur se met alors à lancer une pile complète que personne ne regardera. La vérification tient en une commande, à intégrer aux contrôles de conformité :

Fenêtre de terminal
systemctl get-default # doit répondre multi-user.target sur un serveur

Le rescue target bascule le système dans un état minimal : système de fichiers racine monté, shell root ouvert sur la console, ni réseau ni services. Utile pour réparer /etc/fstab, changer un mot de passe, lancer fsck.

La raison n'est pas une opinion, elle se lit dans la définition des unités. rescue.target ne tire que deux dépendances :

Fenêtre de terminal
systemctl cat rescue.target
[Unit]
Description=Rescue Mode
Requires=sysinit.target rescue.service
After=sysinit.target rescue.service
AllowIsolate=yes

Ni network.target, ni sshd.service, ni quoi que ce soit qui les tire indirectement. Vous pouvez le confirmer sur votre propre machine sans rien casser, la commande ne fait que lire :

Fenêtre de terminal
systemctl list-dependencies rescue.target | grep -cE 'sshd|network-online'
0

Le service que la cible démarre achève la démonstration :

Fenêtre de terminal
systemctl cat rescue.service | grep -E 'ExecStart|StandardInput'
ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue
StandardInput=tty-force

StandardInput=tty-force force le rattachement du shell à la console physique. Le shell de secours n'apparaîtra donc pas dans votre session SSH, qui aura de toute façon disparu avec l'arrêt de sshd.

La commande reste parfaitement légitime, à condition d'être devant la bonne console :

Fenêtre de terminal
sudo systemctl isolate rescue.target

Tous les services non essentiels sont stoppés, un shell root attend sur la console. Sur une machine distante, préférez systématiquement l'entrée en rescue au démarrage décrite juste après : elle vous laisse au moins revenir par un simple redémarrage.

Via le menu GRUB, éditer la ligne linux (touche e) et ajouter à la fin :

systemd.unit=rescue.target

Puis Ctrl+X pour démarrer avec cette option (unique). Très utile quand le système ne termine pas son boot normal.

Si même rescue ne démarre pas (filesystem cassé, par exemple), bascule vers emergency.target qui n'essaie même pas de monter le filesystem en lecture-écriture :

systemd.unit=emergency.target

Le filesystem racine est alors monté en lecture seule. Pour le passer en RW afin de réparer :

Fenêtre de terminal
mount -o remount,rw /

Cas classique : réinitialiser un mot de passe root perdu

Section intitulée « Cas classique : réinitialiser un mot de passe root perdu »
  1. Redémarrer et entrer dans GRUB, interrompre le démarrage auto.

  2. Éditer la ligne linux et ajouter en fin de ligne le paramètre qui correspond à votre famille de distribution. Les deux ne sont pas interchangeables : rd.break est un paramètre de dracut, l'initramfs de RHEL, et Debian n'y répond pas.

    Sur RHEL, Rocky, AlmaLinux et Fedora :

    rd.break

    Sur Debian et Ubuntu, qui utilisent initramfs-tools :

    init=/bin/bash
  3. Démarrer (Ctrl+X). Sur RHEL, le système s'arrête avant de monter / et vous obtenez un shell switch_root:/# dans l'initramfs. Sur Debian, vous obtenez directement un shell root, avec la racine montée en lecture seule.

  4. Monter la racine en lecture-écriture. Dans les deux cas, elle est montée en lecture seule : sans cette étape, passwd échouera.

    Sur RHEL et dérivées, la racine réelle est sous /sysroot, il faut donc s'y enfermer avec chroot :

    Fenêtre de terminal
    mount -o remount,rw /sysroot
    chroot /sysroot

    Sur Debian et Ubuntu, vous êtes déjà sur la racine réelle :

    Fenêtre de terminal
    mount -o remount,rw /
  5. Changer le mot de passe :

    Fenêtre de terminal
    passwd root
  6. Forcer le réétiquetage SELinux (RHEL, Rocky, Fedora uniquement). Sans lui, le nouveau /etc/shadow porte un mauvais contexte de sécurité et le système refuse la connexion au redémarrage :

    Fenêtre de terminal
    touch /.autorelabel
  7. Sortir et redémarrer. Sur RHEL :

    Fenêtre de terminal
    exit # quitte le chroot
    exit # quitte l'initramfs, le boot se poursuit

    Sur Debian et Ubuntu, init=/bin/bash a remplacé le processus d'init : il n'y a pas de shell à quitter, il faut forcer le redémarrage.

    Fenêtre de terminal
    exec /sbin/init # rend la main au démarrage normal

Après un incident, la question naturelle est « qu'est-ce qui s'est passé au démarrage d'avant ? ». La commande existe :

Fenêtre de terminal
journalctl -b -1

Elle échoue pourtant sur beaucoup d'images serveur fraîchement installées, avec un message qui a le mérite d'être explicite :

Specifying boot ID or boot offset has no effect, no persistent journal was found.

La cause est que journald écrit par défaut dans /run/log/journal/, en mémoire. Le paramètre Storage=auto signifie « persistant si le répertoire /var/log/journal/ existe, volatile sinon », et les images minimales de RHEL, AlmaLinux ou Rocky ne le créent pas. Tout le journal disparaît donc à chaque redémarrage, précisément au moment où il devient intéressant.

Créer le répertoire suffit, journald bascule au redémarrage du service :

Fenêtre de terminal
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

Vérifiez que le journal a bien migré sur disque :

Fenêtre de terminal
ls -d /var/log/journal/*
journalctl --disk-usage

Activer la persistance ne récupère pas rétroactivement le démarrage précédent : les journaux d'avant étaient en mémoire, ils sont perdus. Juste après le premier redémarrage, la commande échoue donc encore, mais le message n'est plus le même :

No journal boot entry found for the specified boot (-1).

Cette nuance vaut d'être connue, car les deux messages orientent vers deux diagnostics différents :

MessageCauseAction
no persistent journal was found/var/log/journal/ absent, journal en mémoireCréer le répertoire, redémarrer journald
No journal boot entry found for the specified boot (-1)Journal persistant, mais un seul démarrage enregistréAttendre le prochain redémarrage, rien à corriger

Il faut donc deux redémarrages après l'activation pour que journalctl -b -1 renvoie enfin quelque chose. journalctl --list-boots est la commande qui lève tout doute, en affichant exactement les démarrages disponibles :

IDX BOOT ID FIRST ENTRY LAST ENTRY
-1 e7f529b9f02643ad8e7407a4b124885d Thu 2026-07-23 10:25:55 UTC Thu 2026-07-23 10:26:20 UTC
0 7b5132f8b50b41b18ed98256bb8d9eeb Thu 2026-07-23 10:26:23 UTC Thu 2026-07-23 10:26:40 UTC

L'index -1 est celui que -b -1 désigne. S'il n'apparaît pas dans cette liste, aucune option de journalctl ne le fera surgir.

Ces réflexes séparent un redémarrage maîtrisé d'un coup de dé. Le fil conducteur est le même partout : prévenir avant d'agir et vérifier l'état du système avant comme après. Un reboot n'a jamais réparé un service déjà en échec, il faut donc regarder systemctl list-units --failed en amont, pas espérer que le redémarrage fasse le ménage.

  • Préférez shutdown -r +N à reboot dès qu'il y a d'autres utilisateurs potentiellement connectés.
  • Annoncez une maintenance avec un message explicite dans la commande (-k envoie un wall message sans éteindre, utile pour prévenir sans encore rebooter).
  • Vérifiez systemctl list-units --failed avant un reboot : un service déjà en échec ne redémarrera pas magiquement après le reboot, il faut diagnostiquer avant.
  • Désactivez proprement les services qui ne doivent pas redémarrer (systemctl disable) plutôt que de les kill manuellement à chaque boot.
  • Rendez le journal persistant dès l'installation, sinon journalctl -b -1 ne servira à rien le jour de l'incident.
  • last reboot et last shutdown listent l'historique depuis /var/log/wtmp, indépendamment de journald.

Toute commande d'arrêt ou de bascule de cible doit avoir sa porte de sortie prévue avant de l'exécuter, surtout à distance. Les points suivants répondent à une seule question : que faire si l'opération tourne mal ? Le plus important n'est pas dans une commande mais dans un principe, garder à tout moment un accès qui ne dépende pas du système en cours de manipulation, console physique, IPMI ou console cloud.

  • Annuler un shutdown : sudo shutdown -c tant que l'arrêt n'a pas commencé.

  • Rebooter en target alternatif une seule fois :

    Fenêtre de terminal
    sudo systemctl reboot --boot-loader-menu=10 # affiche le menu GRUB 10 s
  • Protéger le GRUB avec un mot de passe pour empêcher quiconque ayant accès à la console d'entrer en rescue, voir Durcir le bootloader dans le guide BP-028.

  • Garder un accès physique / IPMI / console cloud : si un kernel mis à jour ne boote pas, c'est la seule voie de retour.

Ce tableau réunit les incidents les plus courants autour de l'arrêt, du redémarrage et des cibles systemd. Lisez-le en partant du symptôme observé, la colonne du milieu nomme la cause à confirmer avant d'appliquer l'action. Deux lignes ne sont pas des pannes mais des comportements attendus que l'on prend à tort pour des bugs : la machine injoignable après isolate rescue.target, et le message No journal boot entry found sur un journal qui n'a qu'un seul démarrage enregistré.

SymptômeCause probableAction
reboot rend la main mais la machine ne redémarre pasService bloqué au stop, attend son timeoutAttendre ou forcer : sudo systemctl reboot --force --force
Le système boote en mode rescue sans raison/etc/fstab cassé ou device absentÉditer /etc/fstab, systemctl daemon-reload, puis reboot
shutdown -c n'annule rienLe shutdown a déjà commencé son phase finaleTrop tard, attendre le reboot
Le mot de passe root ne passe pas après passwd rootRelabel SELinux non déclenchéAu prochain boot : touch /.autorelabel avant sortie
Aucune console après boot en rescueLe target nécessite un mot de passe root que vous n'avez pasUtiliser rd.break au niveau initramfs
Le système redémarre en boucle après rebootKernel cassé ou driver manquantGRUB → choisir le kernel précédent (entrée « advanced options »)
systemctl list-units --failed liste plusieurs services après rebootDépendances mal ordonnées ou ressource absentejournalctl -xe -u <service> pour chaque service en échec
La machine est injoignable après systemctl isolate rescue.targetAttendu : la cible n'embarque ni réseau ni sshdPasser par la console physique, IPMI ou console cloud, puis systemctl isolate multi-user.target
journalctl -b -1 répond no persistent journal was found/var/log/journal/ n'existe pas, journald écrit en mémoiremkdir -p /var/log/journal puis systemctl restart systemd-journald
journalctl -b -1 répond No journal boot entry foundJournal persistant, mais un seul démarrage enregistréVérifier avec journalctl --list-boots, rien à corriger
systemctl isolate basic.target refuséAllowIsolate=no sur les cibles intermédiairesIsoler une cible d'état complet (multi-user, graphical, rescue)
Un serveur sans écran démarre en runlevel 5Cible par défaut restée sur graphical.targetsystemctl set-default multi-user.target

Changer le target par défaut est le genre de manipulation qu'on ne veut pas découvrir sur un serveur de production. Ce lab fournit une VM jetable pour lire le target courant avec systemctl get-default, basculer vers multi-user.target avec set-default et confirmer après reboot que le système démarre bien dessus.

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • Quatre commandes principales : shutdown (planifié), reboot (rapide), poweroff (éteindre), systemctl poweroff/reboot (forme systemd).
  • shutdown -r +N "message" est la commande par défaut en production, prévient les utilisateurs, laisse le temps aux services.
  • shutdown -c annule, tant que l'arrêt n'a pas commencé.
  • Targets systemd remplacent les runlevels : multi-user.target, graphical.target, rescue.target, emergency.target. Les runlevels 2, 3 et 4 désignent tous la même cible, ce ne sont plus que des alias.
  • systemctl isolate <target> bascule à la volée sans reboot, mais ne change pas la cible par défaut : set-default s'occupe du prochain démarrage.
  • systemctl isolate rescue.target coupe l'accès distant : la cible n'embarque ni réseau ni sshd, et son shell est forcé sur la console. Depuis SSH, passer par systemd.unit=rescue.target dans GRUB.
  • rd.break dans GRUB permet de réinitialiser un mot de passe root perdu (avec relabel SELinux si applicable).
  • journalctl -b -1 exige un journal persistant : créer /var/log/journal/, puis compter deux redémarrages avant que le boot précédent soit lisible.
  • Une cible graphique sur un serveur ne provoque aucune erreur : Wants=display-manager.service est une dépendance faible. Seul systemctl get-default révèle le réglage.
  • Protéger GRUB par mot de passe en production pour empêcher l'accès rescue non autorisé.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn