Skip to Content

Chapitre 3.5 — systemd & services

⏱️ TL;DRsystemd est le chef d’orchestre de Linux moderne : le premier processus lancé au démarrage (PID 1), celui qui démarre, surveille et redémarre tous les services. Un service, c’est un programme qui tourne en permanence (Nginx, Postgres, ton app Next.js) — et qu’on veut voir redémarrer tout seul au boot et après un crash. On le pilote avec systemctl : start, stop, restart, reload, status, et surtout enable (démarrage automatique au boot — le piège classique est de l’oublier). Les logs se lisent avec journalctl -u <service> (et -f pour suivre en direct). Pour transformer ton app en service, tu écris un petit fichier texte, un unit (/etc/systemd/system/monapp.service), avec où et sous quel utilisateur la lancer, et Restart=always pour qu’elle ressuscite après un crash. C’est la brique qui fera tourner FormaCampus en Partie 9.

🎯 Objectifs

  • Comprendre le rôle de systemd et ce qu’est un service (une unit).
  • Piloter un service avec systemctl : start, stop, restart, reload, status.
  • Ne jamais oublier enable (démarrage au boot) — la différence vitale avec start.
  • Lire les logs d’un service avec journalctl (-u, -f, --since, -e).
  • Écrire un unit file complet pour faire tourner ta propre app en service.

systemd : le chef d’orchestre

Au démarrage du serveur, le noyau Linux lance un seul processus : le PID 1. Sur les distributions modernes (Ubuntu, Debian, la plupart), ce PID 1 est systemd. C’est lui l’ancêtre de tous les processus (revoir l’arbre du Chapitre 3.4) et le gestionnaire de services du système : il décide quoi lancer au démarrage, dans quel ordre, surveille que tout tourne, et relance ce qui tombe.

Chaque chose que systemd gère est une unit. La plus courante est le service (fichiers .service) : un programme de longue durée. Nginx, Postgres, SSH, ton app : tous sont des services gérés par systemd. C’est systemd qui les fait survivre à ta déconnexion et redémarrer au reboot — exactement ce qu’un & ou un nohup ne savent pas faire proprement.

💡 Réflexe — Dès qu’un programme doit tourner en continu en production, la question n’est pas « comment le lancer ? » mais « comment en faire un service ? ». Un service lancé à la main dans un terminal est une bombe à retardement : il meurt à la première déconnexion, au premier crash, au premier reboot. La réponse de prod, c’est toujours systemd.

systemctl : piloter les services

systemctl est la commande unique pour tout piloter. Les verbes essentiels :

sudo systemctl status nginx # ÉTAT du service : actif ? depuis quand ? PID ? 3 dernières lignes de log sudo systemctl start nginx # le DÉMARRER maintenant sudo systemctl stop nginx # l'ARRÊTER maintenant sudo systemctl restart nginx # l'arrêter puis le redémarrer (recharge tout) sudo systemctl reload nginx # RECHARGER sa config SANS l'arrêter (pas de coupure de service)

status est ton tableau de bord : il te dit si le service est active (running) ou failed, depuis combien de temps, son PID, et affiche les dernières lignes de log — souvent assez pour comprendre un problème du premier coup.

💡 Réflexereload plutôt que restart quand c’est possible. reload demande au service de relire sa config sans s’arrêter : aucune coupure. restart le tue et le relance : bref instant d’indisponibilité + toutes les connexions en cours sont perdues. Pour Nginx après un changement de config, reload est la norme ; restart se réserve aux cas où reload ne suffit pas. (Note : tous les services ne savent pas se reloadstatus et la doc du service te le disent.)

enable : le piège qui casse au reboot

Voici la distinction que tout le monde confond au début, et qui provoque des pannes mystérieuses :

  • start démarre le service maintenant, pour cette session. Mais au prochain reboot, il ne repartira PAS.
  • enable l’inscrit pour démarrer automatiquement à chaque boot. Mais ne le démarre pas tout de suite.
sudo systemctl enable nginx # démarrage AUTOMATIQUE au boot (mais pas maintenant) sudo systemctl start nginx # démarrage MAINTENANT (mais pas au prochain reboot) sudo systemctl enable --now nginx # LES DEUX d'un coup : active au boot ET démarre tout de suite sudo systemctl disable nginx # retire du démarrage automatique sudo systemctl is-enabled nginx # vérifier : "enabled" ou "disabled" ?

⚠️ PiègeOublier enable. Scénario classique et cruel : tu installes ton app, tu la start, tout marche, tu es content. Des semaines plus tard, une mise à jour ou une coupure de courant redémarre le serveur… et ton app ne revient pas, parce qu’elle n’était que start, jamais enable. Le site est down « sans raison ». Le réflexe qui évite ça : systemctl enable --now pour tout service de prod, puis teste avec un sudo reboot que tout remonte bien. Un systemctl is-enabled sur tes services critiques fait partie de la checklist de mise en prod.

journalctl : lire les logs

systemd collecte automatiquement la sortie de chaque service (ce que le programme écrit) dans un journal centralisé, le journald. On le consulte avec journalctl. L’option reine est -u (unit), pour cibler un service :

journalctl -u nginx # tous les logs du service nginx (paginés) journalctl -u nginx -e # saute directement à la FIN (-e = end, les plus récents) journalctl -u nginx -f # SUIT le log en DIRECT (-f = follow), comme tail -f journalctl -u nginx --since "10 min ago" # depuis 10 minutes journalctl -u nginx --since today # depuis ce matin journalctl -u nginx --since "2026-07-15 09:00" # depuis une date/heure précise

Le couple status + journalctl est ta méthode de diagnostic universelle pour un service qui déconne : systemctl status <service> pour l’état et un aperçu, journalctl -u <service> -e pour le détail des erreurs, -f pour observer en temps réel pendant que tu reproduis le problème.

🐚 Au terminal — La séquence « mon service ne démarre pas » :

sudo systemctl status monapp # est-il failed ? qu'affiche l'aperçu de log ? journalctl -u monapp -e # le détail de l'erreur (dernières entrées) journalctl -u monapp -f # suivre en direct pendant qu'on tente un restart sudo systemctl restart monapp # relancer, en observant le journal en parallèle

📚 La docman systemctl, man journalctl, et man systemd.service (le format d’un unit file, section par section). systemd est vaste ; on n’en couvre ici que le cœur indispensable au déploiement. Pour les timers (l’équivalent moderne de cron, croisés avec le renouvellement Let’s Encrypt en Partie 8) et les options fines, la doc systemd fait autorité.

Écrire un unit : transformer ton app en service

Voici le cœur pratique du chapitre : rendre ta propre application gérée par systemd. Un service est décrit par un fichier texte, l’unit file, rangé dans /etc/systemd/system/ et nommé <nom>.service. Il se compose de trois sections : [Unit] (métadonnées et dépendances), [Service] (comment lancer le programme), [Install] (comment l’activer au boot).

Exemple complet et commenté pour une app Next.js en production :

[Unit] Description=FormaCampus - front Next.js After=network.target # After : ne démarre ce service qu'une fois le réseau prêt. [Service] Type=simple User=deploy Group=deploy WorkingDirectory=/var/www/formacampus EnvironmentFile=/var/www/formacampus/.env.production ExecStart=/usr/bin/node /var/www/formacampus/server.js Restart=always RestartSec=3 [Install] WantedBy=multi-user.target

Décortiquons les directives qui comptent, dans [Service] :

  • ExecStart : la commande qui lance ton app. Utilise des chemins absolus (/usr/bin/node, pas node) — systemd n’a pas le même PATH que ton shell.
  • User et Group : l’utilisateur sous lequel tourne le service. Jamais root pour une app web : ici deploy. C’est le moindre privilège des Chapitres 3.1 et 3.2 appliqué aux services.
  • WorkingDirectory : le dossier depuis lequel l’app s’exécute (comme si tu avais fait cd dedans avant).
  • EnvironmentFile : le fichier .env d’où charger les variables d’environnement (secrets, NODE_ENV=production, port…). On ne met pas les secrets en clair dans l’unit ; on pointe vers un fichier aux droits restreints (rappel : 600/640, Chapitre 3.3).
  • Restart=always : la directive magique. Si l’app crashe, systemd la relance automatiquement. Avec RestartSec=3, il attend 3 secondes entre deux tentatives (pour ne pas boucler frénétiquement).

Et dans [Install] :

  • WantedBy=multi-user.target : dit à quel moment du démarrage rattacher le service quand on l’enable. multi-user.target = « le système est prêt, en mode serveur multi-utilisateurs » — la cible standard pour un service de fond.

⚠️ PiègeModifier un unit sans faire daemon-reload. systemd met en cache la définition des services. Si tu édites /etc/systemd/system/monapp.service puis fais directement systemctl restart monapp, systemd relance l’ancienne version — tes changements sont ignorés, et tu tournes en rond à te demander pourquoi. Après toute édition d’un unit, il faut recharger la config de systemd :

sudo systemctl daemon-reload # systemd relit les fichiers d'unit (OBLIGATOIRE après édition) sudo systemctl restart monapp # puis on applique

La séquence complète, de A à Z

Mettre un nouveau service en production, dans l’ordre :

# 1. Créer/éditer l'unit sudo nano /etc/systemd/system/formacampus-front.service # (coller l'unit ci-dessus) # 2. Recharger la config de systemd (car on a touché à un unit) sudo systemctl daemon-reload # 3. Activer au boot ET démarrer tout de suite sudo systemctl enable --now formacampus-front # 4. Vérifier que tout va bien sudo systemctl status formacampus-front # doit être "active (running)" journalctl -u formacampus-front -e # jeter un œil aux logs de démarrage

🧭 Sur FormaCampus — C’est ici que tout converge. L’équipe fait tourner deux services systemd : formacampus-front.service (le front Next.js) et formacampus-api.service (l’API Symfony), tous deux en User=deploy, avec Restart=always et un EnvironmentFile pointant vers un .env en 640. Chacun est enable --now, puis l’équipe reboote volontairement le VPS pour vérifier que les deux remontent seuls. Nginx (Partie 7) relaiera ensuite vers ces deux services locaux. Le jour où l’API crashe à 3 h du matin, Restart=always la relance en 3 secondes, et journalctl -u formacampus-api garde la trace de l’incident pour le lendemain. Fini les apps lancées à la main qui meurent au premier hoquet : c’est la définition même de la prod. On construit tout ça en détail en Partie 9.

🔒 Sécurité — Un unit bien écrit est aussi une surface d’attaque réduite : User=deploy (jamais root), un .env aux droits restreints référencé par EnvironmentFile plutôt que des secrets en clair, et — pour aller plus loin — les options de durcissement de systemd (NoNewPrivileges=, ProtectSystem=, PrivateTmp=…) qui cloisonnent encore le service. On les cite ; leur détail relève du durcissement (Partie 5) et de la doc man systemd.exec. Le réflexe minimal, dès maintenant : jamais User=root pour une app.

✏️ Exercices

Exercice 1 — Le service qui ne revient pas. Un collègue a installé une app, l’a lancée avec systemctl start monapp, et tout marchait. Après un reboot du serveur, le site est down. Quel est le problème, comment le confirmer, et comment le corriger définitivement ?

✅ Solution

Le problème : le service a été start mais jamais enable. start ne démarre que pour la session courante ; au reboot, systemd ne le relance pas car il n’est pas inscrit au démarrage automatique.

Confirmer :

sudo systemctl is-enabled monapp # affichera "disabled"

Corriger définitivement :

sudo systemctl enable --now monapp # active au boot ET démarre maintenant sudo systemctl is-enabled monapp # doit maintenant afficher "enabled"

Bonus : refaire un sudo reboot pour vérifier que le service remonte bien tout seul.

Exercice 2 — Écris un unit. Écris un unit systemd minimal mais complet pour une API Node qui se lance avec /usr/bin/node /var/www/api/server.js, tourne sous l’utilisateur deploy, charge son environnement depuis /var/www/api/.env, et redémarre automatiquement en cas de crash.

✅ Solution

[Unit] Description=API Node de production After=network.target [Service] Type=simple User=deploy Group=deploy WorkingDirectory=/var/www/api EnvironmentFile=/var/www/api/.env ExecStart=/usr/bin/node /var/www/api/server.js Restart=always RestartSec=3 [Install] WantedBy=multi-user.target

À déposer dans /etc/systemd/system/api.service, puis : sudo systemctl daemon-reload (car on a créé un unit), et enfin sudo systemctl enable --now api. Les points clés : User=deploy (pas root), Restart=always (résilience au crash), EnvironmentFile (secrets hors de l’unit), WantedBy=multi-user.target (activable au boot).

🧠 Quiz de révision

1. Quelle est la différence entre systemctl start et systemctl enable ?

start démarre le service maintenant, mais il ne repartira pas au prochain reboot. enable l’inscrit pour démarrer automatiquement au boot, mais ne le lance pas tout de suite. Pour les deux d’un coup : systemctl enable --now <service>. Oublier enable est le piège classique qui fait qu’un service ne revient pas après un redémarrage.

2. Comment lit-on les logs d’un service précis, en direct ?

Avec journalctl -u <service> -f : -u cible l’unit (le service voulu), -f suit le journal en temps réel (comme tail -f). Pour aller directement aux dernières entrées sans suivre : -e. Pour filtrer par date : --since.

3. À quoi sert Restart=always dans un unit, et User= ?

Restart=always demande à systemd de relancer automatiquement le service s’il crashe — c’est ce qui rend une app résiliente en prod. User= fixe l’utilisateur sous lequel le service tourne : on met un compte non privilégié (ex. deploy), jamais root, pour limiter les dégâts en cas de compromission (moindre privilège).

4. Pourquoi faut-il faire daemon-reload après avoir édité un unit ?

Parce que systemd met en cache la définition des services. Sans systemctl daemon-reload, un restart relancerait l’ancienne version de l’unit et ignorerait tes modifications. La règle : après toute édition d’un fichier d’unit, sudo systemctl daemon-reload avant de (re)démarrer.

5. Que fait WantedBy=multi-user.target dans la section [Install] ?

Il indique à quel moment du démarrage rattacher le service quand on l’enable. multi-user.target correspond au système prêt en mode serveur (multi-utilisateurs, sans interface graphique) : c’est la cible standard pour un service de fond. C’est cette ligne qui rend le service activable au boot.


Fin de la Partie 3. Tu sais désormais qui habite la machine, qui a le droit de quoi, et comment faire tourner tes apps comme de vrais services. Direction l’accès distant sécurisé : Partie 4 — SSH : accès & durcissement.

Last updated on