Debian 13 : Service ne démarre plus après une modification de configuration — corrigez-le en lisant les bonnes lignes de log (cas n°1)

Cet article vous a aidé ?

Vous avez modifié une configuration. Vous avez agi de manière responsable. Vous avez même laissé un commentaire comme « temporary » qui sera assurément toujours là en 2027. Maintenant le service ne démarre plus, votre monitoring sonne, et systemctl status se montre évasif.

La bonne nouvelle : Debian 13 avec systemd vous fournit tout ce qu’il faut pour résoudre cela rapidement — à condition d’arrêter de lire les mauvaises lignes de log. La mauvaise nouvelle : la plupart des gens font exactement ça, regardent les trois dernières lignes de sortie, puis commencent des sacrifices rituels à « the cache ». Ne le faites pas. Lisez les bonnes lignes, dans le bon ordre, et vous réparerez cela en quelques minutes.

Cas n°1 : modification de configuration → le service ne démarre plus (ce qui s’est réellement passé)

C’est le schéma le plus courant que je vois sur les systèmes Debian : un service est sain, quelqu’un modifie un fichier de configuration, puis redémarre le service. Le redémarrage échoue. L’astreint lance systemctl status, voit « failed with result ‘exit-code’ », et commence à deviner.

La correction se trouve presque toujours dans les logs, mais pas dans la partie que les gens lisent en premier. La ligne utile est généralement :

  • Plus ancienne que la ligne « Main process exited… »
  • Émise par un processus auxiliaire (comme ExecStartPre) qui a testé la config puis s’est arrêté
  • Ou émise par le démon lui‑même, une seule fois, puis enterrée sous le boilerplate systemd

Pour le cas n°1, imaginez un service typique avec une étape de test de configuration :

  • ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on;
  • ExecStart=/usr/sbin/nginx -g daemon on; master_process on;

Le redémarrage échoue non parce que systemd est mystérieux, mais parce que le test de pré‑vol a détecté une erreur de syntaxe, un chemin d’include invalide, ou un problème de permission sur un fichier référencé. Les « bonnes lignes de log » sont celles qui décrivent cet échec de pré‑vol. Votre travail est de les extraire proprement, sans vous noyer dans du bruit sans rapport.

Blague n°1 (courte, pertinente) : Un redémarrage de service, c’est comme un parachute — si vous ignorez l’inspection, vous saurez quand il a marché.

Quelques faits et un peu d’histoire qui expliquent pourquoi les logs ressemblent à ça

Comprendre le pourquoi Debian 13 se comporte ainsi vous rend plus rapide sous pression. Voici des faits concrets qui comptent quand un service refuse de démarrer après une modification de configuration :

  1. systemd est devenu le système d’init par défaut de Debian à partir de Debian 8 (Jessie). Cette décision a standardisé la gestion des services et les attentes en matière de journalisation, mais a aussi déplacé l’endroit où l’on cherche les erreurs.
  2. journald n’est pas un fichier texte. Les logs sont stockés dans un journal binaire et interrogés avec journalctl. Vous pouvez toujours forwarder vers syslog, mais la source canonique est le journal.
  3. systemctl status est un résumé, pas une investigation. Il affiche un extrait tronqué des logs et un état unitaire de haut niveau. Il sert à vous orienter vers des requêtes plus profondes, pas à les remplacer.
  4. Les unités systemd peuvent avoir plusieurs processus avant que le « vrai » démon ne démarre. ExecStartPre, des generators, des scripts wrapper et des fichiers d’environnement peuvent échouer avant même que le PID du service n’existe.
  5. Les codes de sortie sont standardisés, mais souvent trompeurs sans contexte. Un « exit status 1 » peut signifier « erreur de syntaxe », « permission refusée » ou « port déjà utilisé ». Il vous faut le message associé.
  6. Beaucoup de démons sont conçus pour échouer rapidement sur une config invalide. Nginx, Postfix, HAProxy et d’autres refusent volontairement de démarrer si les tests de config échouent — car démarrer avec une config partielle/invalide est pire.
  7. Le packaging Debian tend à ajouter des vérifications de sécurité. Les mainteneurs incluent fréquemment des validations pré‑start dans les unités ou scripts wrapper. C’est un bon point d’ingénierie, mais cela signifie que les erreurs peuvent provenir de scripts que vous n’aviez pas remarqués.
  8. L’ordre des logs peut être trompeur. journald est horodaté, mais des démarrages parallèles et plusieurs processus peuvent s’entrelacer. La « dernière ligne » n’est pas toujours « la cause ».
  9. La limitation de taux est réelle. journald peut rate‑limiter des services bruyants ; la première erreur peut être enregistrée, les 500 suivantes résumées. Si vous ne regardez que le résumé, vous ratez l’indice initial.

Une idée paraphrasée à garder en tête, attribuée correctement : Gene Kim (idée paraphrasée) : la fiabilité s’améliore quand vous créez des boucles de rétroaction rapides et raccourcissez la distance entre le changement et le diagnostic.

Playbook de diagnostic rapide (premières/deuxièmes/troisièmes vérifications)

Ceci est l’ordre qui gagne en production. Il est biaisé pour obtenir la cause racine en moins de cinq minutes, pas pour vous faire sentir occupé.

Premier : confirmez ce que systemd considère comme ayant échoué (vue au niveau de l’unité)

  • Obtenez l’état de l’unité, le code de sortie et la phase qui a échoué (pré‑start vs démarrage principal).
  • Extrait la ligne de commande exacte que systemd a lancée (y compris ExecStartPre).

Deuxième : extrayez la bonne tranche du journal (filtrée par temps et par unité)

  • Interrogez les logs pour cette unité, pour le dernier boot, avec le moins de bruit possible.
  • Puis élargissez la plage temporelle si nécessaire ; n’élargissez pas la portée d’abord.
  • Cherchez la première ligne d’erreur significative, pas la dernière ligne « exited ».

Troisième : lancez manuellement la validation de configuration du démon

  • La plupart des services ont un mode « tester la configuration puis quitter ».
  • Exécutez-le exactement comme le ferait systemd (même utilisateur, même environnement, même chemin de configuration).
  • Si la validation passe manuellement mais échoue sous systemd, suspectez les permissions, les fichiers d’environnement, AppArmor ou des différences de répertoire de travail.

Quatrième : décidez entre corriger, rollback ou contournement temporaire

  • Si c’est une erreur de syntaxe claire : corrigez-la maintenant, puis redémarrez.
  • Si vous n’êtes pas sûr et que la production brûle : faites un rollback vers la dernière config connue bonne et redémarrez.
  • Évitez les contournements « temporaires » comme commenter des étapes de validation sauf si vous comprenez le rayon d’impact.

Tâches pratiques : commandes, sortie attendue et décisions (12+)

Ces tâches sont écrites comme un SRE travaille réellement : lancez une commande, lisez la sortie, prenez une décision. Pas de discours de motivation. Chaque tâche inclut ce que signifie la sortie et ce que vous faites ensuite.

Task 1 : Vérifiez le statut de l’unité (mais lisez‑le correctement)

cr0x@server:~$ systemctl status nginx.service --no-pager
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Mon 2025-12-30 10:14:03 UTC; 42s ago
   Duration: 2.103s
    Process: 21984 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=1/FAILURE)
        CPU: 29ms

Dec 30 10:14:03 server nginx[21984]: nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/app.conf:57
Dec 30 10:14:03 server systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Dec 30 10:14:03 server systemd[1]: nginx.service: Failed with result 'exit-code'.
Dec 30 10:14:03 server systemd[1]: Failed to start nginx.service - A high performance web server and a reverse proxy server.

Ce que cela signifie : L’échec s’est produit dans ExecStartPre, avant le démarrage du démon nginx. C’est un échec de test de configuration, pas un crash en cours d’exécution.

Décision : Ne poursuivez pas les ports, les fichiers PID ou les limites du noyau. Corrigez la ligne de configuration référencée (app.conf:57) et relancez le test de configuration.

Task 2 : Affichez uniquement le journal pour cette unité (la dernière tentative, proprement)

cr0x@server:~$ journalctl -u nginx.service -b --no-pager -n 60
Dec 30 10:14:03 server systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...
Dec 30 10:14:03 server nginx[21984]: nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/app.conf:57
Dec 30 10:14:03 server systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Dec 30 10:14:03 server systemd[1]: nginx.service: Failed with result 'exit-code'.
Dec 30 10:14:03 server systemd[1]: Failed to start nginx.service - A high performance web server and a reverse proxy server.

Ce que cela signifie : Le journal confirme l’erreur de parser exacte. Pas besoin d’inférer.

Décision : Ouvrez le fichier, corrigez la syntaxe, puis testez de nouveau la configuration avant de redémarrer.

Task 3 : Récupérez les logs « depuis le redémarrage » quand le boot est bruyant

cr0x@server:~$ systemctl show -p ActiveEnterTimestampMonotonic nginx.service
ActiveEnterTimestampMonotonic=81234567890
cr0x@server:~$ journalctl -u nginx.service -b --no-pager --since "2 min ago"
Dec 30 10:14:03 server systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...
Dec 30 10:14:03 server nginx[21984]: nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/app.conf:57
Dec 30 10:14:03 server systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Dec 30 10:14:03 server systemd[1]: nginx.service: Failed with result 'exit-code'.

Ce que cela signifie : Vous avez limité les logs par temps plutôt que de traverser tout un boot.

Décision : Si l’erreur n’est pas dans cette fenêtre, élargissez à 10 minutes ; ne retirez pas encore le filtre unité.

Task 4 : Inspectez l’unité pour les vérifications pré‑start et les fichiers d’environnement

cr0x@server:~$ systemctl cat nginx.service
# /lib/systemd/system/nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on;
ExecStart=/usr/sbin/nginx -g daemon on; master_process on;
ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target

Ce que cela signifie : L’échec n’est pas dans le démon long‑cours ; il se situe dans l’étape de validation. De plus, il n’y a pas d’EnvironmentFile= ici, donc moins de variables cachées.

Décision : Exécutez manuellement la commande de pré‑start exacte pour reproduire ; si elle échoue, corrigez la configuration. Si elle réussit, l’échec est environnemental (permissions, AppArmor, chemins d’include).

Task 5 : Lancez manuellement le test de configuration du démon (même commande)

cr0x@server:~$ sudo /usr/sbin/nginx -t -q -g "daemon on; master_process on;"
nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/app.conf:57

Ce que cela signifie : C’est une erreur de parsing déterministe de la configuration. Pas de bizarrerie systemd.

Décision : Corrigez le fichier et la ligne référencés. Ne redémarrez pas en boucle dans l’espoir que « ça se stabilise ». Ce ne sera pas le cas.

Task 6 : Localisez la ligne fautive et validez la structure des includes

cr0x@server:~$ nl -ba /etc/nginx/sites-enabled/app.conf | sed -n '45,70p'
    45  server {
    46      listen 443 ssl;
    47      server_name app.example.internal;
    48      include /etc/nginx/snippets/tls.conf;
    49
    50      location / {
    51          proxy_pass http://127.0.0.1:8080;
    52          proxy_set_header Host $host;
    53      }
    54
    55  }   # end server
    56
    57  }

Ce que cela signifie : Il y a une accolade fermante supplémentaire à la ligne 57.

Décision : Supprimez‑la, enregistrez, relancez le test de configuration. Si vous voyez souvent des déséquilibres d’accolades, adoptez une règle de style : un bloc par fichier, indentation cohérente, et un linter de configuration dans le CI.

Task 7 : Validez à nouveau, puis redémarrez (ne sautez pas l’étape de validation)

cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Ce que cela signifie : Il est maintenant sûr de redémarrer.

Décision : Redémarrez une seule fois. Si le redémarrage échoue maintenant, c’est un problème différent — ne supposez pas que c’est encore la syntaxe de la config.

cr0x@server:~$ sudo systemctl restart nginx.service
cr0x@server:~$ systemctl is-active nginx.service
active

Ce que cela signifie : Le service fonctionne.

Décision : Confirmez qu’il sert du trafic (health check local) et clôturez correctement l’incident.

Task 8 : Quand status est peu utile, affichez les logs complets avec filtrage par priorité

cr0x@server:~$ journalctl -u nginx.service -b -p warning --no-pager
Dec 30 10:14:03 server nginx[21984]: nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/app.conf:57

Ce que cela signifie : Vous avez filtré sur warning et supérieur, donc vous ne lisez pas le « Started… » verbeux.

Décision : Utilisez‑le quand une unité est bavarde. Si rien n’apparaît au niveau warning/error, vous loggez peut‑être ailleurs ou vous avez un échec silencieux avant l’initialisation du logging.

Task 9 : Confirmez quels fichiers de config ont changé récemment (attrapez le vrai coupable)

cr0x@server:~$ sudo find /etc/nginx -type f -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort | tail -n 8
2025-12-30 10:12 /etc/nginx/sites-enabled/app.conf
2025-12-29 18:41 /etc/nginx/nginx.conf
2025-12-10 09:03 /etc/nginx/snippets/tls.conf
2025-11-21 15:22 /etc/nginx/mime.types

Ce que cela signifie : Vous pouvez corréler l’échec de démarrage avec l’édition la plus récente.

Décision : Si l’erreur référence un fichier inclus, vérifiez aussi son mtime. « Je n’ai changé qu’une ligne » n’est rarement toute l’histoire.

Task 10 : Si ce n’est pas une syntaxe, vérifiez les « permission denied » (classique après un durcissement)

cr0x@server:~$ journalctl -u nginx.service -b --no-pager -n 30
Dec 30 10:20:11 server nginx[22310]: nginx: [emerg] open() "/etc/nginx/snippets/tls.conf" failed (13: Permission denied)
Dec 30 10:20:11 server systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
cr0x@server:~$ namei -l /etc/nginx/snippets/tls.conf
f: /etc/nginx/snippets/tls.conf
drwxr-xr-x root root /
drwxr-xr-x root root etc
drwxr-xr-x root root nginx
drwx------ root root snippets
-rw------- root root tls.conf

Ce que cela signifie : Les permissions du répertoire empêchent nginx (qui tourne en www-data après démarrage) ou son test de pré‑start de lire les includes.

Décision : Corrigez les permissions au minimum requis. Habituellement : bit d’exécution sur les répertoires pour la traversée et lecture du fichier pour l’utilisateur ou le groupe du service.

Task 11 : Validez l’utilisateur runtime et l’isolation du service

cr0x@server:~$ systemctl show nginx.service -p User -p Group -p DynamicUser -p ProtectSystem -p ReadWritePaths
User=
Group=
DynamicUser=no
ProtectSystem=no
ReadWritePaths=

Ce que cela signifie : Cette unité particulière n’utilise pas les directives de sandboxing systemd. Si vous voyez ProtectSystem=strict ou des ReadWritePaths serrés, les lectures/écritures de config peuvent être bloquées.

Décision : Si le sandboxing est activé, alignez‑le sur les besoins du démon plutôt que de le désactiver sans réfléchir. Ajoutez des ReadOnlyPaths/ReadWritePaths explicites dans un override.

Task 12 : Interprétez les raisons d’échec du point de vue de systemd (codes de sortie et signaux)

cr0x@server:~$ systemctl show nginx.service -p ExecMainStatus -p ExecMainCode -p Result
ExecMainStatus=1
ExecMainCode=exited
Result=exit-code

Ce que cela signifie : Le processus est sorti normalement avec le statut 1. Pas SIGKILL, pas OOM, pas timeout.

Décision : Concentrez‑vous sur la configuration, les paramètres et les permissions. Si vous voyez ExecMainCode=killed ou Result=timeout, c’est une branche différente.

Task 13 : Si le service flappe, arrêtez la boucle de redémarrages pendant que vous lisez les logs

cr0x@server:~$ sudo systemctl reset-failed nginx.service
cr0x@server:~$ sudo systemctl stop nginx.service
cr0x@server:~$ systemctl status nginx.service --no-pager
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: inactive (dead)

Ce que cela signifie : Vous empêchez systemd de spammer les redémarrages pendant que vous déboguez. Cela rend aussi le journal plus lisible.

Décision : Faites cela quand Restart=always crée du bruit et de la charge. Puis redémarrez intentionnellement quand vous avez une correction.

Task 14 : Comparez les changements de config en toute sécurité avec les métadonnées dpkg (vérification liée au packaging)

cr0x@server:~$ dpkg -S /etc/nginx/nginx.conf
nginx-common: /etc/nginx/nginx.conf
cr0x@server:~$ sudo ls -l /etc/nginx/nginx.conf*
-rw-r--r-- 1 root root 1492 Dec 29 18:41 /etc/nginx/nginx.conf
-rw-r--r-- 1 root root 1479 Nov 21 15:22 /etc/nginx/nginx.conf.dpkg-dist

Ce que cela signifie : Vous avez peut‑être un fichier par défaut fourni par la distro ou un fichier en attente de fusion. Cela peut interagir avec votre changement.

Décision : Si le service a commencé à échouer après une mise à jour plus une édition de config, examinez .dpkg-dist/.dpkg-old et réconciliez consciemment.

Task 15 : Quand les logs manquent, confirmez la persistance journald et la limitation de taux

cr0x@server:~$ sudo grep -E '^(Storage|SystemMaxUse|RateLimitIntervalSec|RateLimitBurst)=' /etc/systemd/journald.conf | sed '/^#/d;/^$/d'
Storage=auto
RateLimitIntervalSec=30s
RateLimitBurst=1000
cr0x@server:~$ journalctl --disk-usage
Archived and active journals take up 384.0M in the file system.

Ce que cela signifie : Si Storage=volatile, vous perdez les logs au redémarrage. Si la limitation de taux est basse, vous pouvez manquer des erreurs répétées.

Décision : En production, conservez les logs sur disque et taillez-les de façon appropriée. Pour le débogage, augmentez temporairement les limites de taux si un service spamme, mais corrigez ensuite la cause du spam.

Blague n°2 (courte, pertinente) : « Ça marchait hier » n’est pas une preuve ; c’est juste le témoignage d’un témoin à la mémoire douteuse.

Trois mini-récits d’entreprise (et leurs enseignements)

Mini-récit 1 : L’incident causé par une mauvaise hypothèse

L’équipe avait une flotte Debian exécutant un mélange de services web et API. Un après‑midi, une modification de configuration de routine est sortie : mise à jour des suites TLS, standardisation entre environnements. Quelqu’un a redémarré nginx sur un canary. Ça a échoué. Ils ont exécuté nginx -t manuellement ; ça a réussi. L’hypothèse s’est formée instantanément : « systemd est cassé sur cet hôte. »

Ils ont creusé les versions de paquet, les paramètres du noyau, même SELinux (qui n’était d’ailleurs pas activé). Pendant ce temps, le trafic a été drainé du nœud et l’autoscaler s’est alarmé. Ils ont continué à retenter des redémarrages « juste pour voir », ce qui est une excellente façon d’écraser la seule bonne ligne d’erreur avec une pile de redémarrages.

La correction était embarrassante de simplicité : l’unité systemd utilisait un chemin de config différent via un fichier d’environnement. Pas malveillant — juste historique. Le nginx -t manuel testait /etc/nginx/nginx.conf ; systemd testait /etc/nginx/nginx-canary.conf. Le fichier canary incluait un snippet qui n’existait pas sur cet hôte.

La leçon n’est pas « ne pas utiliser de fichiers d’environnement ». C’est : n’assumez jamais que votre reproduction manuelle correspond au service manager. Extrait la commande exacte ExecStartPre/ExecStart avec systemctl cat et exécutez celle‑ci. Si un fichier d’environnement existe, affichez‑le, et arrêtez de deviner.

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Un groupe plateforme a décidé de « accélérer les déploiements » en passant de restart à reload quand c’était possible. Reload est moins coûteux : moins de churn de connexions, moins d’erreurs transitoires. Bonne intention. Puis ils l’ont généralisé à plusieurs services avec un script one‑size‑fits‑most.

Un service, un broker de messages, acceptait les signaux de reload mais ne rechargeait la configuration que partiellement. Pour certains paramètres il fallait un redémarrage complet, mais la commande de reload retournait quand même succès. Au fil du temps, la dérive de configuration s’est installée : la configuration en mémoire ne correspondait plus à celle sur disque, et on a perdu confiance dans les deux.

Finalement, un changement de configuration a introduit un paramètre qui aurait échoué à une validation de démarrage frais. Le reload n’a rien fait d’utile, a dit « OK », et le système a continué avec l’ancienne configuration. Quelques jours plus tard, un redémarrage de l’hôte a eu lieu. Le service a dû démarrer à froid, a lu la mauvaise config, et a refusé de démarrer. Cet échec est survenu pendant une fenêtre de maintenance, lieu favori pour rencontrer ses erreurs passées.

La leçon : reload n’est pas un déjeuner gratuit. Si vous choisissez reload comme optimisation, vous devez aussi imposer la validation de config dans le processus de changement et périodiquement effectuer des redémarrages contrôlés pour prouver que la configuration est réellement démarrable.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la situation

Un service interne lié à la finance tournait sur Debian, soutenu par une base de données et un front web. Ils avaient une politique de changement peu glamour : chaque modification de config devait être commitée dans un repo, et l’outil de déploiement exécutait toujours le test de configuration intégré du service avant de toucher systemd. Si le test échouait, le changement n’était tout simplement pas déployé.

Les gens se plaignaient. « Ça nous ralentit. » « Je peux le tester dans ma tête. » Le classique. Puis un jour un ingénieur senior a modifié une config en direct pendant un incident — parce que le service se comportait mal et qu’il fallait une atténuation rapide. L’édition comportait une erreur de quote subtile. Le prochain redémarrage aurait tué le service entièrement.

L’outil de déploiement a refusé d’appliquer le changement sans un test de config passant. C’était le but : des garde‑fous quand le stress rend tout le monde négligent. Ils ont corrigé la quote, retesté, puis redémarré en toute sécurité. Personne n’a été rappelé deux fois.

La leçon : la pratique ennuyeuse n’est pas le repo. C’est la porte de validation automatique plus un chemin de rollback prévisible. Ces deux éléments empêchent qu’une petite erreur devienne une panne.

Erreurs fréquentes : symptôme → cause racine → correction

Voici les récidivistes. Si votre service ne démarre plus après une modification de configuration, vous tomberez probablement dans l’une de ces catégories.

1) Symptom : systemctl status affiche « failed (Result: exit-code) » sans erreur utile

Cause racine : Vous ne voyez que le résumé. La ligne significative est plus ancienne ou tronquée.

Correction : Interrogez directement le journal et élargissez la tranche.

cr0x@server:~$ journalctl -u myservice.service -b --no-pager -n 200
...look for the first real error line...

2) Symptom : le service échoue instantanément après le redémarrage ; les logs mentionnent ExecStartPre

Cause racine : La validation pré‑start a échoué (syntax error, include manquant, directive invalide).

Correction : Exécutez la même validation manuellement et corrigez la configuration avant de redémarrer.

cr0x@server:~$ systemctl cat myservice.service | sed -n '/ExecStartPre/p'
ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on;

3) Symptom : le test de config passe manuellement, échoue sous systemd

Cause racine : Chemin de config différent, utilisateur différent, environnement différent ou restrictions du sandbox.

Correction : Extrait la commande et l’environnement exacts de l’unité ; exécutez en tant qu’utilisateur du service.

cr0x@server:~$ systemctl show myservice.service -p Environment -p EnvironmentFiles
Environment=
EnvironmentFiles=/etc/default/myservice (ignore_errors=no)

4) Symptom : « Permission denied » sur includes, certificats, sockets, fichiers PID

Cause racine : Changement de durcissement (chmod/chown), nouveau chemin aux permissions restrictives, ou mismatch de l’utilisateur du service.

Correction : Tracez les permissions du chemin avec namei -l ; corrigez le bit d’exécution sur les répertoires et la lecture des fichiers.

5) Symptom : « Address already in use » après une modification de config

Cause racine : Vous avez changé l’écoute / le port ; un autre service l’occupe ; ou l’ancienne instance ne s’est pas arrêtée proprement.

Correction : Identifiez qui tient le port ; choisissez de revenir au port précédent, d’arrêter le service en conflit, ou de corriger l’activation de socket.

cr0x@server:~$ sudo ss -ltnp | grep ':443 '
LISTEN 0      511          0.0.0.0:443        0.0.0.0:*    users:(("haproxy",pid=1203,fd=7))

6) Symptom : l’unité affiche Result=timeout

Cause racine : Le démon bloque au démarrage (attente DNS, stockage, migrations) ou le timeout systemd est trop agressif pour un cold start.

Correction : Lisez les logs autour du blocage, puis ajustez TimeoutStartSec seulement si le travail de démarrage est légitime et borné.

7) Symptom : après une modification de config, le service « démarre » mais ne fonctionne pas

Cause racine : Vous avez utilisé reload et supposé que tout s’appliquait ; ou la config est acceptée mais sémantiquement incorrecte.

Correction : Exécutez un health check applicatif et confirmez la config active avec l’introspection du service si disponible. Redémarrez si nécessaire.

8) Symptom : le journal n’a aucune entrée pour l’unité

Cause racine : Le service logge vers un fichier (ou stdout est redirigé), journald est volatile, ou l’unité ne s’est jamais exécutée à cause d’un échec de dépendance.

Correction : Vérifiez systemctl list-dependencies et les paramètres de journald ; inspectez les fichiers de logs traditionnels si configurés.

Listes de contrôle / plan étape par étape (corrections sûres et rollback)

Étape par étape : diagnostiquer et corriger sans agiter le système

  1. Arrêtez la boucle de redémarrages si elle est présente. Si l’unité flappe, mettez‑la en pause pour pouvoir lire des logs stables.
  2. Lisez le résumé de l’unité. Identifiez si ExecStartPre a échoué ou si le processus principal est mort.
  3. Interrogez journald par unité et par boot. Ne commencez pas par les logs globaux.
  4. Extrait la commande de démarrage exacte. Lisez systemctl cat et vérifiez les drop‑ins.
  5. Exécutez le test de config du service manuellement. Même arguments, même chemin de config.
  6. Corrigez la plus petite chose qui permet au service de démarrer. Évitez les refontes pendant la réponse à l’incident.
  7. Redémarrez une fois, puis vérifiez au niveau applicatif. « active (running) » n’est pas la même chose que « sert du trafic ».
  8. Notez la ligne de cause racine. Collez la chaîne d’erreur exacte dans la note d’incident. Le vous du futur remerciera le vous du présent.

Plan de rollback : quand vous n’êtes pas sûr que votre correction est correcte

Si vous ne pouvez pas prouver la correction rapidement, faites un rollback. N’« itérez pas en production » pendant que le pager hurle.

  1. Sauvegardez la configuration cassée. Copiez‑la avec un timestamp pour l’analyser plus tard.
  2. Restaurez la dernière configuration connue bonne depuis votre repo ou sauvegardes.
  3. Validez la configuration. Lancez toujours le mode de test du démon.
  4. Redémarrez le service et vérifiez.
  5. Seulement après la récupération : déboguez le changement cassé dans un environnement contrôlé.
cr0x@server:~$ sudo cp -a /etc/nginx/sites-enabled/app.conf /root/app.conf.broken.$(date +%F-%H%M%S)
cr0x@server:~$ sudo cp -a /root/rollback/app.conf /etc/nginx/sites-enabled/app.conf
cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
cr0x@server:~$ sudo systemctl restart nginx.service
cr0x@server:~$ systemctl is-active nginx.service
active

Quand vous devez garder un service partiellement up (contrôle des dégâts)

Parfois vous ne pouvez pas tout corriger immédiatement, mais vous pouvez réduire l’impact :

  • Restaurez une configuration minimale qui sert une page de maintenance.
  • Désactivez le virtual host cassé tout en gardant les autres en service.
  • Dirigez temporairement le trafic hors du nœud, corrigez en isolation, puis réintégrez.

N’éliminez pas les étapes de validation pour « faire démarrer » à moins d’être certain que le démon ne démarrera pas dans un état corrompu. Ce chemin mène à une perte de données, et vous n’apprécierez pas le postmortem.

FAQ

1) Pourquoi systemctl status n’est‑il pas suffisant ?

Parce qu’il est volontairement compact. Il montre une petite queue de logs et un résumé d’état de l’unité. Utilisez‑le pour trouver le nom de l’unité, la phase d’échec, puis pivotez vers journalctl -u pour le vrai diagnostic.

2) Quelle est la meilleure commande journalctl pour cette situation ?

Habituellement :

cr0x@server:~$ journalctl -u myservice.service -b --no-pager -n 200

Si c’est verbeux, ajoutez -p warning ou restreignez par temps avec --since.

3) Comment savoir si l’échec est dû à la config ou à l’exécution ?

Cherchez si ExecStartPre a échoué (config/validation) versus le processus principal qui démarre puis meurt (runtime). systemctl status vous indique généralement quel processus a échoué.

4) Pourquoi le test de configuration manuel réussit parfois alors que systemd échoue ?

Environnement différent. systemd peut utiliser un fichier d’environnement, un répertoire de travail différent, du sandboxing, ou un contexte utilisateur différent. Reproduisez toujours en utilisant la ligne de commande exacte du fichier d’unité.

5) Comment voir les drop‑in overrides qui peuvent changer le comportement ?

cr0x@server:~$ systemctl status myservice.service --no-pager
...look for "Drop-In:" lines...
cr0x@server:~$ systemctl cat myservice.service
...includes /etc/systemd/system/myservice.service.d/*.conf if present...

6) Quand dois‑je utiliser reload plutôt que restart ?

Seulement quand le service documente que reload applique les changements que vous avez faits, et que vous disposez d’une étape de validation. Si vous avez un doute, redémarrez pendant une fenêtre sûre ou après avoir drainé le trafic.

7) Que faire s’il n’y a aucun log pour l’unité ?

Alors soit l’unité ne s’est pas exécutée, soit journald ne conserve pas les logs, soit les logs vont ailleurs (comme /var/log/*). Vérifiez les dépendances et les paramètres de journald, et inspectez les logs fichiers si le service les configure.

8) Comment détecter rapidement si c’est un problème de permissions ?

Cherchez « Permission denied » dans le journal, puis tracez le chemin de fichier avec namei -l. Les problèmes de permissions viennent souvent d’un bit d’exécution manquant sur un répertoire ou d’un durcissement qui a oublié l’utilisateur du service.

9) Quelle est la façon la plus sûre d’éviter cette classe de panne ?

Automatisez la validation de configuration (mode test du démon) avant restart/reload, gardez les configs sous contrôle de version, et rendez le rollback trivial. L’objectif est d’attraper la ligne cassée avant qu’elle n’atteigne systemd.

Conclusion : étapes suivantes pour éviter la répétition des incidents

Un service Debian 13 qui échoue après une modification de configuration n’est rarement un mystère. C’est généralement une ligne d’erreur précise que vous n’avez pas extraite proprement. Lisez l’unité pour savoir ce qui a été exécuté. Lisez le journal limité à l’unité pour savoir ce qui a échoué. Puis validez la config manuellement en utilisant la commande exacte que systemd utilise.

Actions pratiques :

  • Ajoutez une étape de test de configuration avant déploiement pour chaque service qui le supporte.
  • Formez votre équipe à traiter systemctl status comme un pointeur, pas comme un diagnostic final.
  • Faites du rollback une opération de première classe (copier, restaurer, valider, redémarrer).
  • Standardisez un runbook « diagnostic rapide » et gardez‑le près de la rotation du pager.

Faites cela, et la prochaine fois qu’un service refusera de démarrer, vous passerez votre temps à corriger le vrai problème — pas à discuter avec un écran de résumé.

← Précédent
Proxmox « cluster non prêt — pas de quorum ? » : restaurer le quorum sans empirer
Suivant →
Scrub ZFS lent : distinguer la lenteur normale d’un vrai problème

Laisser un commentaire