Les bases de systemd : gerer ses services Linux

Credit : Logo officiel

Les bases de systemd : gerer ses services Linux

Dylan D. — Agent Support Technique Serveur Linux 1978 mots 10 min de lecture

Les bases de systemd : gerer ses services Linux

Vendredi 23h, un client m'appelle : son site WordPress repond plus. Je me connecte en SSH au VPS Debian 12, je tape systemctl status nginx et la, le verdict tombe en deux secondes : Active: failed (Result: exit-code). Trois minutes plus tard apres avoir lu les logs avec journalctl -u nginx -n 50, je vois le probleme (un fichier de config corrompu apres un apt upgrade mal gere). Sans systemd, j'aurais cherche dans dix repertoires de logs differents.

C'est exactement pour ca que je commence chaque diagnostic par systemctl et journalctl. En 2026, sur Debian 12, Ubuntu 24.04, Rocky Linux 9 et a peu pres toutes les distros serveur, c'est systemd qui tient les rennes : Nginx, PHP 8.3-FPM, MariaDB, Redis, fail2ban, ton app Node.js, ton agent CrowdSec... tout passe par lui.

systemctl : la commande centrale

Gerer les services au quotidien

Les operations de base que je tape vingt fois par jour :

# Demarrer, arreter, redemarrer
systemctl start nginx
systemctl stop nginx
systemctl restart nginx

# Recharger la config sans couper le service (zero downtime)
systemctl reload nginx

# Activer/desactiver au demarrage du serveur
systemctl enable nginx
systemctl disable nginx

# Combo : activer ET demarrer maintenant
systemctl enable --now nginx

# Verifier l'etat
systemctl status nginx

La difference entre restart et reload est cruciale. reload envoie un signal SIGHUP au processus, qui relit sa config sans tuer les connexions en cours. restart arrete tout puis redemarre, donc tu coupes les visiteurs. Sur un site en production avec du trafic, je fais toujours reload quand le service le supporte (Nginx, PHP-FPM, sshd...).

Sortie typique de systemctl status nginx quand tout va bien :

# nginx.service - A high performance web server and a reverse proxy server
#      Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
#      Active: active (running) since Wed 2026-05-07 14:22:18 CEST; 3 days ago
#        Docs: man:nginx(8)
#    Main PID: 1234 (nginx)
#       Tasks: 5 (limit: 4915)
#      Memory: 12.4M
#         CPU: 1min 42.318s

Les infos importantes a regarder : Loaded (le service est-il connu ?), Active (running, failed, inactive ?), Main PID (utile pour strace ou lsof), et Memory/CPU pour reperer une fuite memoire naissante.

Explorer les services en cours

# Lister tous les services actifs
systemctl list-units --type=service --state=active

# Services en echec (toujours bon a verifier apres un reboot)
systemctl list-units --type=service --state=failed

# Services qui ont ete charges mais sont inactifs
systemctl list-units --type=service --state=inactive

# Dependances d'un service
systemctl list-dependencies nginx

# Que depend DE ce service ?
systemctl list-dependencies nginx --reverse

# Reponses booleennes pour scripts
systemctl is-active nginx
systemctl is-enabled nginx
systemctl is-failed nginx

Un truc que je fais systematiquement apres un reboot ou une mise a jour majeure : systemctl --failed. Ca te montre direct si un service a pas reussi a demarrer. Sur un serveur freshly upgrade vers Debian 12, j'ai souvent du php8.2-fpm en failed parce que la config a evolue vers PHP 8.3.

journalctl : lire les logs comme un pro

journalctl c'est l'outil pour consulter les logs systemd. Sous-utilise par la plupart des gens qui continuent a faire tail -f /var/log/syslog. Pourtant journalctl est beaucoup plus puissant.

# Logs d'un service
journalctl -u nginx
journalctl -u php8.3-fpm

# En temps reel (comme tail -f)
journalctl -u nginx -f

# Par date
journalctl -u nginx --since "2026-05-07 08:00" --until "2026-05-07 12:00"
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since yesterday

# Dernieres N lignes
journalctl -u nginx -n 50

# Logs du demarrage actuel
journalctl -b

# Logs du boot precedent (utile apres un crash)
journalctl -b -1

# Par priorite (emerg, alert, crit, err, warning, notice, info, debug)
journalctl -p err
journalctl -p warning -u nginx

# Sortie JSON pour parsing
journalctl -u nginx -o json --since "1 hour ago"

# Filtrer par PID ou utilisateur
journalctl _PID=1234
journalctl _UID=33

# Espace utilise par les logs
journalctl --disk-usage

# Nettoyer
journalctl --vacuum-time=7d
journalctl --vacuum-size=500M

Sur un VPS IONOS j'ai eu le cas ou les logs systemd prenaient 4.2 Go a force d'accumuler les erreurs PHP. Un coup de journalctl --vacuum-size=500M et c'etait regle. Pour limiter ca de maniere permanente, edite /etc/systemd/journald.conf :

[Journal]
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=2week
ForwardToSyslog=no

Puis systemctl restart systemd-journald. Tes logs seront capes a 500 Mo et retenus 2 semaines max.

Anatomie d'un unit file

Un unit file decrit comment systemd doit gerer un service. Trois sections cles : [Unit], [Service], [Install].

Creer un service personnalise pour une app Node.js

Admettons une app Express qui ecoute sur le port 3000. Cree /etc/systemd/system/mon-app.service :

[Unit]
Description=Mon application Node.js
Documentation=https://github.com/moi/mon-app
After=network.target
Wants=network-online.target
Requires=mariadb.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/mon-app
EnvironmentFile=/etc/mon-app/env.conf
ExecStart=/usr/bin/node server.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
StartLimitInterval=60
StartLimitBurst=3
StandardOutput=journal
StandardError=journal
SyslogIdentifier=mon-app

# Securite (durcissement)
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/www/mon-app/storage
ProtectHome=true
PrivateTmp=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6

# Limites de ressources
MemoryMax=512M
CPUQuota=80%
TasksMax=100

[Install]
WantedBy=multi-user.target

Quelques points cles :

Active et demarre :

systemctl daemon-reload
systemctl enable mon-app
systemctl start mon-app
systemctl status mon-app

Le daemon-reload c'est OBLIGATOIRE apres chaque modif d'un unit file. Oublie pas, sinon systemd continue d'utiliser l'ancienne version en cache et tu vas te demander pourquoi tes changements s'appliquent pas.

Les timers : remplacer cron proprement

Les timers systemd sont une alternative moderne a cron. Mieux integres, journalises, avec gestion des dependances et rattrapage si le serveur etait eteint.

Le service dans /etc/systemd/system/backup.service :

[Unit]
Description=Sauvegarde quotidienne des bases
Wants=mariadb.service
After=mariadb.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=root
Nice=10
IOSchedulingClass=idle

Puis le timer dans /etc/systemd/system/backup.timer :

[Unit]
Description=Lancer la sauvegarde tous les jours a 3h

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=300
AccuracySec=1m

[Install]
WantedBy=timers.target

Active le timer :

systemctl daemon-reload
systemctl enable --now backup.timer

Verifie les timers actifs et leur prochaine execution :

systemctl list-timers --all
# NEXT                        LEFT          LAST                        PASSED       UNIT              ACTIVATES
# Thu 2026-05-08 03:00:00 CEST 12h left      Wed 2026-05-07 03:00:13 CEST 11h ago      backup.timer      backup.service
# Thu 2026-05-08 06:30:42 CEST 16h left      Wed 2026-05-07 06:30:42 CEST 8h ago       apt-daily.timer   apt-daily.service

Pourquoi les timers plutot que cron ?

  1. Journalisation : journalctl -u backup.service te donne tout l'historique des executions et leurs sorties.
  2. Persistent=true : si le serveur etait eteint au moment prevu, le timer rattrape l'execution au reboot. Cron oublie.
  3. RandomizedDelaySec : repartit la charge si tu as plusieurs serveurs (utile pour pas saturer un point de stockage commun).
  4. Dependances : tu peux specifier qu'un timer doit attendre que MariaDB soit demarre.
  5. Reutilisable : meme service appele par un timer ou manuellement avec systemctl start backup.service.

Erreurs courantes et leur fix

Failed to start service.service: Unit not found

Cause : tu as cree le unit file mais oublie le daemon-reload. Ou le fichier a un nom incorrect (doit finir par .service).

Fix :

systemctl daemon-reload
ls -la /etc/systemd/system/mon-app.service
systemctl status mon-app.service

Job for nginx.service failed because the control process exited with error code

Cause : la config Nginx a une erreur de syntaxe. Classique apres un edit a la main.

Fix :

nginx -t
# nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/monsite:42
journalctl -u nginx -n 30
# Lis la stack et corrige la ligne incriminee

start request repeated too quickly

Cause : ton service crashe en boucle, systemd a abandonne apres StartLimitBurst tentatives.

Fix :

systemctl reset-failed mon-app
journalctl -u mon-app -n 100 --no-pager
# Identifie la cause du crash, corrige, puis :
systemctl start mon-app

Failed to connect to bus: No such file or directory

Cause : tu es dans un container ou un chroot sans systemd.

Fix : utilise service nginx restart ou directement les binaires. systemd ne tourne pas dans tous les environnements.

Le service demarre mais s'arrete tout de suite

Cause : Type=simple declare mais le binaire fork (cas typique avec PHP-FPM mal configure) ou inversement.

Fix : verifie le Type= dans le unit file. Pour les daemons qui forkent, utilise Type=forking avec un PIDFile=.

Depannage : la checklist

Quand un service deconne, je suis toujours cette sequence :

# 1. Etat actuel
systemctl status mon-app

# 2. Logs recents
journalctl -u mon-app -n 50 --no-pager

# 3. Logs depuis le dernier demarrage
journalctl -u mon-app -b

# 4. Recharger apres modif
systemctl daemon-reload

# 5. Reset si stuck en failed
systemctl reset-failed mon-app

# 6. Analyser le temps de demarrage du systeme
systemd-analyze
systemd-analyze blame | head -20
systemd-analyze critical-chain

systemd-analyze blame est super pour identifier ce qui ralentit le boot. Sur un serveur que j'ai recupere, j'ai vu que apt-daily.service prenait 2 minutes au demarrage. Apres investigation, c'etait un cache APT corrompu. apt clean && apt update et hop, boot 4x plus rapide.

Cas pratique : monitorer ses services

Un workflow que j'ai mis en place sur tous mes VPS : un check automatise toutes les 5 minutes pour detecter les services en panne et m'alerter par webhook. Cree /usr/local/bin/check-services.sh :

#!/bin/bash
set -euo pipefail

SERVICES=(nginx php8.3-fpm mariadb redis-server fail2ban)
WEBHOOK="https://hooks.slack.com/services/XXX/YYY/ZZZ"
FAILED=()

for s in "${SERVICES[@]}"; do
    if ! systemctl is-active --quiet "$s"; then
        FAILED+=("$s")
    fi
done

if [ ${#FAILED[@]} -gt 0 ]; then
    MESSAGE="Services en panne sur $(hostname) : ${FAILED[*]}"
    curl -s -X POST -H 'Content-Type: application/json' \
        -d "{\"text\":\"$MESSAGE\"}" "$WEBHOOK"
    echo "$(date) $MESSAGE" >> /var/log/check-services.log
fi

Planifie-le via un timer systemd (boucle bouclee) :

# /etc/systemd/system/check-services.timer
[Unit]
Description=Check services every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target
systemctl enable --now check-services.timer

Bonus : les targets et le boot

systemd organise le demarrage avec des targets (equivalents des runlevels SysV). Les principaux :

# Voir le target par defaut
systemctl get-default

# Changer (utile pour desactiver un GUI sur un serveur)
systemctl set-default multi-user.target

# Changer immediatement (sans reboot)
systemctl isolate multi-user.target

# Booter en mode rescue depuis GRUB :
# Ajouter "systemd.unit=rescue.target" a la ligne kernel

C'est rare d'avoir a toucher aux targets sur un serveur de prod, mais utile a connaitre quand un boot deconne.

Pour aller plus loin

Le reflexe systemd

Maitriser systemctl et journalctl, c'est gagner 80% du temps de diagnostic sur un serveur Linux moderne. Cree-toi des unit files propres pour tes apps custom, utilise les timers a la place de cron quand tu veux du logging serieux, et durcis chaque service avec les options de sandbox. Plus tu pratiques, plus ces commandes deviennent un reflexe quasi-musculaire. Et c'est exactement comme ca qu'a 23h un vendredi tu retrouves l'origine d'une panne en trois minutes.

# Articles similaires

Sur les memes sujets et plus loin